Spring和Hibernate整合后,通过Hibernate API进行数据库操作时发现每次都要opensession,close,beginTransaction,commit,这些都是重复的工作,我们可以把事务管理部分交给spring框架完成。
配置事务(xml方式)
使用spring管理事务后在dao中不再需要调用beginTransaction和commit,也不需要调用session.close(),使用API sessionFactory.getCurrentSession()来替代sessionFactory.openSession()
1 @Repository 2 public class UserDaoImpl implements UserDao { 3 @Autowired 4 private SessionFactory sessionFactory; 5 6 public User findUserById(int id) { 7 Session session = sessionFactory.getCurrentSession(); 8 User user = (User)session.get(User.class, id); 9 session.delete(user); 10 11 return user; 12 } 13 }
采用getCurrentSession()创建的session会绑定到当前线程中,而采用openSession()创建的session则不会。
采用getCurrentSession()创建的session在commit或rollback时会自动关闭,而采用openSession()创建的session必须手动关闭。
使用getCurrentSession()需要在hibernate.cfg.xml文件中加入如下配置:
* 如果使用的是本地事务(jdbc事务)
<property name="hibernate.current_session_context_class">thread</property>
* 如果使用的是全局事务(jta事务)
<property name="hibernate.current_session_context_class">jta</property>
如果采用的时Hibernate4,使用getCurrentSession()必须配置事务,否则无法取到session
applicationContext.xml配置
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans 3 xmlns="http://www.springframework.org/schema/beans" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xmlns:p="http://www.springframework.org/schema/p" 6 xmlns:context="http://www.springframework.org/schema/context" 7 xmlns:aop="http://www.springframework.org/schema/aop" 8 xmlns:tx="http://www.springframework.org/schema/tx" 9 xmlns:jpa="http://www.springframework.org/schema/data/jpa" 10 xmlns:cache="http://www.springframework.org/schema/cache" 11 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 12 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 13 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 14 http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd 15 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd 16 http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> 17 18 <context:component-scan base-package="dao"/> 19 <context:component-scan base-package="service"/> 20 <context:component-scan base-package="test"/> 21 22 <context:property-placeholder location="classpath:dbcp.properties"/> 23 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 24 <property name="driverClassName" value="${driverClassName}" /> 25 <property name="url" value="${url}" /> 26 <property name="username" value="${mysqlusername}" /> 27 <property name="password" value="${mysqlpassword}" /> 28 <property name="maxActive" value="${maxActive}" /> 29 <property name="maxIdle" value="${maxIdle}" /> 30 <property name="minIdle" value="${minIdle}" /> 31 <property name="maxWait" value="${maxWait}" /> 32 <property name="initialSize" value="${initialSize}" /> 33 <property name="logAbandoned" value="${logAbandoned}" /> 34 <property name="removeAbandoned" value="${removeAbandoned}" /> 35 <property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" /> 36 <property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" /> 37 <property name="numTestsPerEvictionRun" value="${numTestsPerEvictionRun}" /> 38 </bean> 39 40 <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 41 <property name="dataSource" ref="dataSource" /> 42 43 <property name="hibernateProperties"> 44 <props> 45 <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> 46 <prop key="hibernate.show_sql">true</prop> 47 <prop key="current_session_context_class">thread</prop> 48 </props> 49 </property> 50 51 <property name="packagesToScan"> 52 <list> 53 <value>po</value> 54 </list> 55 </property> 56 </bean> 57 58 59 <!--hibernate4必须配置为开启事务 否则 getCurrentSession()获取不到--> 60 <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 61 <property name="sessionFactory" ref="sessionFactory"></property> 62 </bean> 63 64 <tx:advice id="txAdvice" transaction-manager="txManager"> 65 <tx:attributes> 66 <tx:method name="find*" propagation="REQUIRED" /> 67 <tx:method name="*" read-only="true"/> 68 </tx:attributes> 69 </tx:advice> 70 71 <aop:config proxy-target-class="true"> 72 <!-- <aop:advisor advice-ref="txAdvice" pointcut="execution(* dao.*.*(..))"/> --> 73 <aop:pointcut expression="execution(* dao.*.*(..))" id="pointcut"/> 74 <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/> 75 </aop:config> 76 77 </beans>
Spring中Propagation类的事务属性详解:
PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
配置事务(声明方式)
需要在xml配制中设置<tx:annotation-driven transaction-manager="transactionManager">
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans 3 xmlns="http://www.springframework.org/schema/beans" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xmlns:p="http://www.springframework.org/schema/p" 6 xmlns:context="http://www.springframework.org/schema/context" 7 xmlns:aop="http://www.springframework.org/schema/aop" 8 xmlns:tx="http://www.springframework.org/schema/tx" 9 xmlns:jpa="http://www.springframework.org/schema/data/jpa" 10 xmlns:cache="http://www.springframework.org/schema/cache" 11 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 12 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 13 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 14 http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd 15 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd 16 http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> 17 18 <context:component-scan base-package="dao"/> 19 <context:component-scan base-package="service"/> 20 <context:component-scan base-package="test"/> 21 22 <context:property-placeholder location="classpath:dbcp.properties"/> 23 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 24 <property name="driverClassName" value="${driverClassName}" /> 25 <property name="url" value="${url}" /> 26 <property name="username" value="${mysqlusername}" /> 27 <property name="password" value="${mysqlpassword}" /> 28 <property name="maxActive" value="${maxActive}" /> 29 <property name="maxIdle" value="${maxIdle}" /> 30 <property name="minIdle" value="${minIdle}" /> 31 <property name="maxWait" value="${maxWait}" /> 32 <property name="initialSize" value="${initialSize}" /> 33 <property name="logAbandoned" value="${logAbandoned}" /> 34 <property name="removeAbandoned" value="${removeAbandoned}" /> 35 <property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" /> 36 <property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" /> 37 <property name="numTestsPerEvictionRun" value="${numTestsPerEvictionRun}" /> 38 </bean> 39 40 <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 41 <property name="dataSource" ref="dataSource" /> 42 43 <property name="hibernateProperties"> 44 <props> 45 <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> 46 <prop key="hibernate.show_sql">true</prop> 47 <prop key="current_session_context_class">thread</prop> 48 </props> 49 </property> 50 51 <property name="packagesToScan"> 52 <list> 53 <value>po</value> 54 </list> 55 </property> 56 </bean> 57 58 59 <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 60 <property name="sessionFactory" ref="sessionFactory"></property> 61 </bean> 62 <tx:annotation-driven transaction-manager="txManager"/> 63 64 </beans>
事物注解方式: @Transactional
当标于类前时,标示类中所有方法都进行事物处理,以下代码在service层进行事务处理(给Service层配置事务是比较好的方式,因为一个Service层方法操作可以关联到多个DAO的操作。在Service层执行这些Dao操作,多DAO操作有失败全部回滚,成功则全部提交。)
1 @Service 2 @Transactional 3 public class UserServiceImpl implements UserService { 4 @Autowired 5 private UserDao userDao; 6 7 public User getUserById(int id) { 8 return userDao.findUserById(id); 9 } 10 }
当类中某些方法不需要事物时:
1 @Service 2 @Transactional 3 public class UserServiceImpl implements UserService { 4 @Autowired 5 private UserDao userDao; 6 7 @Transactional(propagation = Propagation.NOT_SUPPORTED) 8 public User getUserById(int id) { 9 return userDao.findUserById(id); 10 } 11 }
@Transactional(propagation=Propagation.REQUIRED)
如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
@Transactional(propagation=Propagation.NOT_SUPPORTED)
容器不为这个方法开启事务
@Transactional(propagation=Propagation.REQUIRES_NEW)
不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
@Transactional(propagation=Propagation.MANDATORY)
必须在一个已有的事务中执行,否则抛出异常
@Transactional(propagation=Propagation.NEVER)
必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS)
如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.
事物超时设置:
@Transactional(timeout=30) //默认是30秒
事务隔离级别:
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
读取未提交数据(会出现脏读, 不可重复读) 基本不使用
@Transactional(isolation = Isolation.READ_COMMITTED)
读取已提交数据(会出现不可重复读和幻读)
@Transactional(isolation = Isolation.REPEATABLE_READ)
可重复读(会出现幻读)
@Transactional(isolation = Isolation.SERIALIZABLE)
串行化
MYSQL: 默认为REPEATABLE_READ级别
SQLSERVER: 默认为READ_COMMITTED
脏读 : 一个事务读取到另一事务未提交的更新数据
不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说,
后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次
读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
幻读 : 一个事务读到另一个事务已提交的insert数据