Spring-事务
事务作用
使数据库数据从一种状态变为另一种状态的过程不被打扰
并发下事务可能产生的问题
1、脏读:事务A读到了事务B还未提交的数据(解决办法:read commited,就是一个事务修改结束提交后才能读数据)
2、不可重复读: 一个事务中的两次相同查询出现不同的结果,意思是,中途被别的事务修改。重复查询 出现问题
(解决办法:repeatbale read,意思是在读数据的事务开始时,不允许修改操作)
3、幻读:事务A读到的数据,准备发生修改时,发现修改的影响数量和开始读到的数据不同。原因是事务B发生了插入或者删除操作。(解决办法:serializable序列化。使得事务不能并行执行,只能串行执行,效率低下)
事务隔离级别
1、DEFAULT 默认
2、READ_UNCOMMITED,读未提交,最低级,什么都可能发生
3、READ_COMMITED,读已提交,事务A修改结束后才能读,能解决脏读问题,但可能发生不可重复读和幻读问题
4、REPEATABLE_READ,可重复读,事务A在查询过程中事务B不能修改,能解决不可重复读问题,但可能发生幻读
5、SERLALIZABLE,串行化,解决幻读问题
编程式事务控制的三大对象
1、PlatformTransactionalManager:平台事务管理器
PlatformTransactionManager 是接口类型,不同的 Dao 层技术则有不同的实现类,例如:Dao 层技术是jdbc
或 mybatis 时:org.springframework.jdbc.datasource.DataSourceTransactionManager
Dao 层技术是hibernate时:org.springframework.orm.hibernate5.HibernateTransactionManager
2、TransactionDefination:事务的定义信息对象
设置事务隔离级别
设置事务传播行为:
REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中(A调用B,A存在事务,则B加入A中)。一般的选择(默认值)
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务,A调用B,A没有事务,则B也以非事务方式运行)
3、TransactionStatus:事务的运行状态
xml方式实现事务
1、导入maven坐标
< dependency>
< groupId> org. springframework< / groupId>
< artifactId> spring- tx< / artifactId>
< version> 5.0 .5 . RELEASE < / version>
< / dependency>
< dependency>
< groupId> org. aspectj< / groupId>
< artifactId> aspectjweaver< / artifactId>
< version> 1.8 .4 < / version>
< / dependency>
2、配置xml
< ? xml version= "1.0" encoding= "UTF-8" ? >
< beans xmlns= "http://www.springframework.org/schema/beans"
xmlns : xsi= "http://www.w3.org/2001/XMLSchema-instance"
xmlns : aop= "http://www.springframework.org/schema/aop"
xmlns : context= "http://www.springframework.org/schema/context"
xmlns : tx= "http://www.springframework.org/schema/tx"
xsi : schemaLocation= "
http : / / www. springframework. org/ schema/ beans http: / / www. springframework. org/ schema/ beans/ spring- beans. xsd
http : / / www. springframework. org/ schema/ aop http: / / www. springframework. org/ schema/ aop/ spring- aop. xsd
http : / / www. springframework. org/ schema/ context http: / / www. springframework. org/ schema/ context/ spring- context. xsd
http : / / www. springframework. org/ schema/ tx http: / / www. springframework. org/ schema/ tx/ spring- tx. xsd
">
< ! -- 组件扫描-- >
< context: component- scan base- package = "cn.sp.tx" / >
< bean id= "dataSource" class = "com.mchange.v2.c3p0.ComboPooledDataSource" >
< property name= "driverClass" value= "com.mysql.jdbc.Driver" / >
< property name= "jdbcUrl" value= "jdbc:mysql://localhost:3306/spring_test" / >
< property name= "user" value= "root" / >
< property name= "password" value= "123456" / >
< / bean>
< bean id= "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate" >
< property name= "dataSource" ref= "dataSource" / >
< / bean>
< ! -- 配置平台事务管理器-- >
< bean id= "transactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
< property name= "dataSource" ref= "dataSource" / >
< / bean>
< ! -- 通知 事务的增强-- >
< tx: advice id= "txAdvice" transaction- manager= "transactionManager" >
< ! -- 设置事务的属性信息-- >
< tx: attributes>
< tx: method name= "transfer" isolation= "REPEATABLE_READ" propagation= "REQUIRED" read- only= "false" / >
< / tx: attributes>
< / tx: advice>
< ! -- 配置事务的aop织入-- >
< aop: config>
< aop: pointcut id= "txPointcut" expression= "execution(* cn.sp.tx.service.impl.*.*(..))" / >
< aop: advisor advice- ref= "txAdvice" pointcut- ref= "txPointcut" / >
< / aop: config>
< / beans>
3、Dao
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public int out ( String outMan, double money ) {
return jdbcTemplate. update ( "update account set money=money-? where name=?" , money, outMan) ;
}
@Override
public int in ( String inMan, double money) {
return jdbcTemplate. update ( "update account set money=money+? where name=?" , money, inMan) ;
}
}
4、Service
@Service
public class AccountServiceImpl implements AccountService {
private static final Logger log = LoggerFactory. getLogger ( AccountServiceImpl. class) ;
@Autowired
private AccountDao accountDao;
@Override
public void transfer ( String outMan, String inMan, double money ) {
log. info ( "开始" ) ;
accountDao. out ( outMan, money) ;
accountDao. in ( inMan, money) ;
log. info ( "结束" ) ;
}
}
5、测试
@RunWith ( SpringJUnit4ClassRunner. class)
@ContextConfiguration ( { "classpath:spring-tx.xml" } )
public class TestTx {
private static final Logger log = LoggerFactory. getLogger ( TestTx. class) ;
@Autowired
private AccountService accountService;
@Test
public void testTx ( ) {
try {
accountService. transfer ( "tom" , "lucy" , 500 ) ;
} catch ( Exception e) {
log. error ( null , e) ;
}
}
}
注解方式实现事务
1、配置xml
< ? xml version= "1.0" encoding= "UTF-8" ? >
< beans xmlns= "http://www.springframework.org/schema/beans"
xmlns : xsi= "http://www.w3.org/2001/XMLSchema-instance"
xmlns : aop= "http://www.springframework.org/schema/aop"
xmlns : context= "http://www.springframework.org/schema/context"
xmlns : tx= "http://www.springframework.org/schema/tx"
xsi : schemaLocation= "
http : / / www. springframework. org/ schema/ beans http: / / www. springframework. org/ schema/ beans/ spring- beans. xsd
http : / / www. springframework. org/ schema/ aop http: / / www. springframework. org/ schema/ aop/ spring- aop. xsd
http : / / www. springframework. org/ schema/ context http: / / www. springframework. org/ schema/ context/ spring- context. xsd
http : / / www. springframework. org/ schema/ tx http: / / www. springframework. org/ schema/ tx/ spring- tx. xsd
">
< ! -- 组件扫描-- >
< context: component- scan base- package = "cn.sp.tx" / >
< bean id= "dataSource" class = "com.mchange.v2.c3p0.ComboPooledDataSource" >
< property name= "driverClass" value= "com.mysql.jdbc.Driver" / >
< property name= "jdbcUrl" value= "jdbc:mysql://localhost:3306/spring_test" / >
< property name= "user" value= "root" / >
< property name= "password" value= "123456" / >
< / bean>
< bean id= "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate" >
< property name= "dataSource" ref= "dataSource" / >
< / bean>
< ! -- 配置平台事务管理器-- >
< bean id= "transactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
< property name= "dataSource" ref= "dataSource" / >
< / bean>
< ! -- 事物的注解驱动-- >
< tx: annotation- driven transaction- manager= "transactionManager" / >
2、service
@Service ( "accountServiceAnno" )
@Transactional ( isolation = Isolation. REPEATABLE_READ )
public class AccountServiceAnnoImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
@Transactional ( isolation = Isolation. READ_COMMITTED , propagation = Propagation. REQUIRED )
public void transfer ( String outMan, String inMan, double money ) {
accountDao. out ( outMan, money) ;
accountDao. in ( inMan, money) ;
}
}