事务控制
- 编程式
- 注解式
- 声明式
ACID原则
- Atomicity:原子性
- Consistency:一致性
- Isolation:隔离性
- Durability:持久性
TransactionDefinition定义的事务传播属性
编号 | 传播属性 | 描述 |
---|---|---|
1 | PROPAGATION_REQUIRED | 如果存在事务,则支持当前事务。如果没有当前事务,则开启新的事务 |
2 | PROPAGATION_SUPPORTS | 如果存在事务,则支持当前事务。如果没有当前事务,则非事务地执行 |
3 | PROPAGATION_MANDATORY | 如果存在事务,则支持当前事务。如果没有活动事务,则抛出异常 |
4 | PROPAGATION_REQUIRED_NEW | 总是开启新的事务。如果已经存在事务,则将已存在的事务挂起 |
5 | PROPAGATION_NOT_SUPPORTED | 总是非事务地执行,并挂起任何存在的事务 |
6 | PROPAGATION_NEVER | 总是非事务地执行,如果存在活动事务,则抛出异常 |
7 | PROPAGATION_NESTED | 如果存在活动事务,则将其运行在一个嵌套事务中。如果没哟活动的事务,则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行 |
TransactionDefinition定义的事务隔离级别
编号 | 事务隔离级别 | 描述 |
---|---|---|
1 | ISOLATION_DEFAULT | 默认的隔离级别,使用数据库默认的事务隔离级别 |
2 | ISOLATION_READ_UNCOMMITTED | 最低的隔离级别,允许其他事务访问当前的事务未提交的数据。会产生脏读、不可重复读,幻读 |
3 | ISOLATION_READ_COMMITTED | 当前事务修改的数据提交后才能被下一个事务读取。下一个事务不能读取当前事务未提交的数据。可防止脏读,可能出现不可重复读、幻读 |
4 | ISOLATION_REPEATABLE_READ | 可防止脏读、不可重复读,可能出现幻读 |
5 | ISOLATION_SERIALIZABLE | 最可靠的事务隔离级别,事务处理为顺序执行。可防止脏读、不可重复读幻读 |
说明:其他代码同上一篇
编程式事务控制
配置数据源,spring-jdbc.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 在开发之中C3P0数据库连接池使用非常广泛 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/> <!-- 驱动程序 -->
<property name="jdbcUrl" value="jdbc:mysql:*****/mldn"/> <!-- 连接地址 -->
<property name="user" value="root"/> <!-- 用户名 -->
<property name="password" value="*****"/> <!-- 密码 -->
<property name="maxPoolSize" value="1"/> <!-- 最大连接数 -->
<property name="initialPoolSize" value="1"/> <!-- 初始化大小 -->
<property name="minPoolSize" value="1"/> <!-- 最小连接数 -->
<property name="maxIdleTime" value="10"/> <!-- 等待时间 -->
</bean>
<!-- 配置JdbcTemplate模版的处理对象,该对象如果要想使用一定要配置数据库连接 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/> <!-- 配置数据源 -->
</bean>
</beans>
定义数据源的管理类
spring-transaction.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 进行事务管理的配置定义,必须配置PlatformTransactionManager接口子类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/> <!-- 定义要管理的DataSource -->
</bean>
</beans>
业务层接口
package cn.mldn.mldnspring.service;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import cn.mldn.mldnspring.cache.NewsEditCache;
import cn.mldn.mldnspring.vo.News;
@CacheConfig(cacheNames="news") // 进行该接口缓存的统一配置
public interface INewsService {
/**
* 根据ID查询数据
* @param nid 新闻编号
* @return 新闻数据对象
*/
@Cacheable(key = "#nid", unless="#result==null")
public News get(long nid) ;
/**
* 数据更新操作
* @param vo 要更新的数据
* @return 更新后的数据
*/
@NewsEditCache
public News edit(News vo) ;
/**
* 删除新闻数据
* @param nid 新闻编号
* @return 删除成功返回true,否则返回false
*/
@CacheEvict(key="#nid")
public boolean delete(long nid) ;
}
业务层实现类
编程式事务控制写在接口实现类
在查询方法中设置只读事务
package cn.mldn.mldnspring.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import cn.mldn.mldnspring.dao.INewsDAO;
import cn.mldn.mldnspring.service.INewsService;
import cn.mldn.mldnspring.vo.News;
@Service
public class NewsServiceImpl implements INewsService {
@Autowired
private INewsDAO newsDAO;
@Autowired // 可以注入的只是一个接口的实例化对象,但是这些对象还需要配置隔离级别、传播属性
private PlatformTransactionManager transactionManager;
@Override
public News get(long nid) {
News vo = null;
// TransactionDefinition通过此类设置传播属性、隔离级别、是否为只读、超时访问
DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
// 设置传播属性,表示必须有一个事务启动
transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 隔离级别一定要使用默认的隔离级别进行控制
transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
transactionDefinition.setReadOnly(true); // 只读操作
// 获取事务的提交状态
TransactionStatus transactionStatus = this.transactionManager.getTransaction(transactionDefinition);
try {
vo = this.newsDAO.findById(nid);
this.transactionManager.commit(transactionStatus); // 提交事务
} catch (Exception e) {
this.transactionManager.rollback(transactionStatus); // 回滚到指定的提交点
}
return vo;
}
@Override
public News edit(News vo) {
if (this.newsDAO.doUpdate(vo)) {
return vo;
}
return null;
}
@Override
public boolean delete(long nid) {
boolean flag = false;
// TransactionDefinition通过此类设置传播属性、隔离级别、是否为只读、超时访问
DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
// 设置传播属性,表示必须有一个事务启动
transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 隔离级别一定要使用默认的隔离级别进行控制
transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
// 获取事务的提交状态
TransactionStatus transactionStatus = this.transactionManager.getTransaction(transactionDefinition);
try {
flag = this.newsDAO.doRemove(nid);
this.transactionManager.commit(transactionStatus); // 提交事务
} catch (Exception e) {
e.printStackTrace();
this.transactionManager.rollback(transactionStatus); // 回滚到指定的提交点
}
return flag;
}
}
事务注解
注解的事务控制写在业务层接口
加事务注解的接口
package cn.mldn.mldnspring.service;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import cn.mldn.mldnspring.cache.NewsEditCache;
import cn.mldn.mldnspring.vo.News;
@CacheConfig(cacheNames="news") // 进行该接口缓存的统一配置
public interface INewsService {
/**
* 根据ID查询数据
* @param nid 新闻编号
* @return 新闻数据对象
*/
@Cacheable(key = "#nid", unless="#result==null")
@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
public News get(long nid) ;
/**
* 数据更新操作
* @param vo 要更新的数据
* @return 更新后的数据
*/
@NewsEditCache
@Transactional(propagation=Propagation.REQUIRED)
public News edit(News vo) ;
/**
* 删除新闻数据
* @param nid 新闻编号
* @return 删除成功返回true,否则返回false
*/
@CacheEvict(key="#nid")
@Transactional(propagation = Propagation.REQUIRED)
public boolean delete(long nid) ;
}
接口实现类
package cn.mldn.mldnspring.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.mldn.mldnspring.dao.INewsDAO;
import cn.mldn.mldnspring.service.INewsService;
import cn.mldn.mldnspring.vo.News;
@Service
public class NewsServiceImpl implements INewsService {
@Autowired
private INewsDAO newsDAO;
@Override
public News get(long nid) {
return this.newsDAO.findById(nid);
}
@Override
public News edit(News vo) {
if (this.newsDAO.doUpdate(vo)) {
return vo;
}
return null;
}
@Override
public boolean delete(long nid) {
return this.newsDAO.doRemove(nid);
}
}
声明式事务控制
spring-transaction.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: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-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- 进行事务管理的配置定义,必须配置PlatformTransactionManager接口子类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/> <!-- 定义要管理的DataSource -->
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- 事务控制专门提供有切面程序类 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes> <!-- 配置事务控制属性,事务控制是以业务层的方法为主的,方法名称按照统一标准定义 -->
<tx:method name="add*" propagation="REQUIRED"/> <!-- 设置了事务传播属性 -->
<tx:method name="delete*" propagation="REQUIRED" /> <!-- 设置了事务传播属性 -->
<tx:method name="edit*" propagation="REQUIRED"/> <!-- 设置了事务传播属性 -->
<tx:method name="get*" propagation="REQUIRED" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 定义事务要控制的切面表达式,即:在此切面范围内定义的业务方法事务控制生效 -->
<aop:pointcut expression="execution(public * cn.mldn..service..*.*(..))" id="myPointcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"/>
</aop:config>
</beans>