Spring
1:对每一个服务层类Bean配置一个代理:
a.首先创建一个maven quick-start 项目,然后配置依赖包:
mysql-connector,spring-context,spring-orm,hibernate,
hibernate-core,dbcp2(数据源)
b.在test数据库中编写数据库脚本并执行,以及编写applicationContext.xml文件(在src目录下):
DROP TABLE IF EXISTS account;
CREATE TABLE account (
accountId int primary key auto_increment,
accountname varchar(20),
money int not null
);
INSERT INTO ACCOUNT(ACCOUNTNAME,MONEY) VALUES('zhangsan',100);
INSERT INTO ACCOUNT(ACCOUNTNAME,MONEY) VALUES('lisi',100);
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id="dataSource"
class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver">
property>
<property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8&serverTimezone=GMT">property>
<property name="username" value="root">property>
<property name="password" value="mysqladmin">property>
bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
prop>
<prop key="hibernate.show_sql">trueprop>
props>
property>
<property name="mappingResources">
<list>
<value>kai/SpringTransaction1/Account.hbm.xmlvalue>
list>
property>
bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
bean>
<bean id="accountDAO" class="kai.SpringTransaction1.AccountDAO">
<property name="sessionFactory" ref="sessionFactory" />
bean>
<bean id="accountServiceTarget" class="kai.SpringTransaction1.AccountService">
<property name="accountDAO" ref="accountDAO" />
bean>
<bean id="accountService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="accountServiceTarget" />
<property name="proxyInterfaces" value="kai.SpringTransaction1.IAccountService" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIREDprop>
props>
property>
bean>
beans>
c.编写Account类
package kai.SpringTransaction1;
public class Account implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 909891879728703117L;
private Integer accountId;
private String accountname;
private Integer money;
// Property accessors
public Integer getAccountId() {
return this.accountId;
}
public void setAccountId(Integer accountId) {
this.accountId = accountId;
}
public String getAccountname() {
return this.accountname;
}
public void setAccountname(String accountname) {
this.accountname = accountname;
}
public Integer getMoney() {
return this.money;
}
public void setMoney(Integer money) {
this.money = money;
}
// Constructors
/** default constructor */
public Account() {
}
/** full constructor */
public Account(String accountname, Integer money) {
this.accountname = accountname;
this.money = money;
}
}
d.编写AccountDAO和IAccountService,AccountService和Account.hbm.xml,因为是基于代理的,因此服务层必须要有接口,即必须有IAccountService,不能直接代理AccountService。
package kai.SpringTransaction1;
import org.hibernate.SessionFactory;
public class AccountDAO {
public SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory=sessionFactory;
}
@SuppressWarnings("deprecation")
public void addMoney(Integer accountId, int money) {
Account ac=(Account) sessionFactory.getCurrentSession().get(Account.class, accountId);
ac.setMoney(money+ac.getMoney());
sessionFactory.getCurrentSession().update(ac,accountId);
}
public void subMoney(Integer accountId, int money) {
Account ac=(Account) sessionFactory.getCurrentSession().get(Account.class, accountId);
ac.setMoney(ac.getMoney()-money);
sessionFactory.getCurrentSession().update(ac,accountId);
}
}
package kai.SpringTransaction1;
public interface IAccountService {
public void transfer(Integer fromAccountId, Integer toAccountId, int money) ;
}
package kai.SpringTransaction1;
public class AccountService implements IAccountService{
private AccountDAO accountDAO;
/**
* 通过 Spring 将 DAO 注入到 Service
*
* @param accountDAO
*
*/
public void setAccountDAO(AccountDAO accountDAO) {
this.accountDAO = accountDAO;
}
/**
* 转账方法包括两个原子方法:转出方法和转入方法
*
* @param fromAccountId
* @param toAccountId
* @param money
*/
public void transfer(Integer fromAccountId, Integer toAccountId, int money) {
accountDAO.subMoney(fromAccountId, money);
accountDAO.addMoney(toAccountId, money);
}
}
"1.0" encoding="utf-8"?>
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
"kai.SpringTransaction1.Account" table="account" catalog="test">
"accountId" type="java.lang.Integer">
"accountId" />
"native" />
"accountname" type="java.lang.String">
"accountname" length="20" />
"money" type="java.lang.Integer">
"money" length="20" />
e.编写测试类
package kai.SpringTransaction1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
ApplicationContext act = new FileSystemXmlApplicationContext(
"src/applicationContext.xml");
IAccountService accountService = (IAccountService) act
.getBean("accountService");
try {
// 帐号1转账1元至帐号2
accountService.transfer(1, 2, 1);
} catch (Exception e) {
System.out.println("转账失败");
}
}
}
f.运行:查看数据库可知钱成功转账,若将测试类中改为从账户1转到不存在的张户2,则1的钱也不会减少。
2.对服务层所有bean配置同一个代理:
只需将1中的applicationContext.xml文件修改为如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id="dataSource"
class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver">
property>
<property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8&serverTimezone=GMT">property>
<property name="username" value="root">property>
<property name="password" value="mysqladmin">property>
bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
prop>
<prop key="hibernate.show_sql">trueprop>
props>
property>
<property name="mappingResources">
<list>
<value>kai/SpringTransaction1/Account.hbm.xmlvalue>
list>
property>
bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
bean>
<bean id="accountDAO" class="kai.SpringTransaction1.AccountDAO">
<property name="sessionFactory" ref="sessionFactory" />
bean>
<bean id="accountServiceTarget" class="kai.SpringTransaction1.AccountService">
<property name="accountDAO" ref="accountDAO" />
bean>
<bean id="transactionBase"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
lazy-init="true" abstract="true">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIREDprop>
props>
property>
bean>
<bean id="accountService" parent="transactionBase">
<property name="target" ref="accountServiceTarget" />
bean>
beans>
3.基于拦截器的实现,也是只需要修改applicationContext.xml文件:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id="dataSource"
class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver">
property>
<property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8&serverTimezone=GMT">property>
<property name="username" value="root">property>
<property name="password" value="mysqladmin">property>
bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
prop>
<prop key="hibernate.show_sql">trueprop>
props>
property>
<property name="mappingResources">
<list>
<value>kai/SpringTransaction1/Account.hbm.xmlvalue>
list>
property>
bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
bean>
<bean id="accountDAO" class="kai.SpringTransaction1.AccountDAO">
<property name="sessionFactory" ref="sessionFactory" />
bean>
<bean id="accountService" class="kai.SpringTransaction1.AccountService">
<property name="accountDAO" ref="accountDAO" />
bean>
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIREDprop>
props>
property>
bean>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*Servicevalue>
list>
property>
<property name="interceptorNames">
<list>
<value>transactionInterceptorvalue>
list>
property>
bean>
beans>
4.使用AOP方式实现:
在1的基础上修改applicationContext.xml文件以及引入依赖包:aspectj和aspectjweaver。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean id="dataSource"
class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver">
property>
<property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8&serverTimezone=GMT">property>
<property name="username" value="root">property>
<property name="password" value="mysqladmin">property>
bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
prop>
<prop key="hibernate.show_sql">trueprop>
props>
property>
<property name="mappingResources">
<list>
<value>kai/SpringTransaction1/Account.hbm.xmlvalue>
list>
property>
bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
bean>
<bean id="accountDAO" class="kai.SpringTransaction1.AccountDAO">
<property name="sessionFactory" ref="sessionFactory" />
bean>
<bean id="accountService" class="kai.SpringTransaction1.AccountService">
<property name="accountDAO" ref="accountDAO" />
bean>
<tx:advice id="TestAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="*" propagation="REQUIRED" />
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="services"
expression="execution(* kai.SpringTransaction1.AccountService.*(..))" />
<aop:advisor pointcut-ref="services" advice-ref="TestAdvice" />
aop:config>
beans>
5.注解式事务:(这是我觉得最优雅的):
修改applicationContext.xml文件同时在需要加事务控制的方法上加上@Transactional注解。此处即在AccountService的transfer方法上加上@Transactional注解。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean id="dataSource"
class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver">
property>
<property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8&serverTimezone=GMT">property>
<property name="username" value="root">property>
<property name="password" value="mysqladmin">property>
bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
prop>
<prop key="hibernate.show_sql">trueprop>
props>
property>
<property name="mappingResources">
<list>
<value>kai/SpringTransaction1/Account.hbm.xmlvalue>
list>
property>
bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
bean>
<bean id="accountDAO" class="kai.SpringTransaction1.AccountDAO">
<property name="sessionFactory" ref="sessionFactory" />
bean>
<bean id="accountService" class="kai.SpringTransaction1.AccountService">
<property name="accountDAO" ref="accountDAO" />
bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
beans>
补充说明:
1.@Transactional
(1)这个注解放在类上面,会对这个类中的所有public方法都起作用;
(2)放在方法上,只有当这个方法是public方法才起作用。
(3)事务的传播性:@Transactional(propagation=Propagation.REQUIRED)
(4)事务的隔离级别:@Transactional(isolation = Isolation.READ_UNCOMMITTED)
参考文章:
http://blog.csdn.net/it_man/article/details/5074371
http://blog.csdn.net/lifangshui/article/details/6324348
http://blog.csdn.net/qh_java/article/details/51811533