事务

事务用来保证数据的完整性和一致性。

事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。
1、原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
2、一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
3、隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作对并发执行的各个事务之间不能互相干扰。
4、持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。

Spring事务管理

Spring事务管理即支持编程式事务管理,也支持声明式事务。
1、编程式事务:将事务管理代码嵌入到业务方法中来控制事务的提交和回滚。
2、声明式事务:将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。Spring通过AOP框架支持声明式事务。

Spring事务示例(XML)

先定义一个applicationContext.xml

 <context:component-scan base-package="com.hzg.spring.jdbc"/>  

 <!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<!-- Connection Info -->
<property name="driverClass" value="${db.driverClass}" />
<property name="jdbcUrl" value="${db.url}" />
<property name="user" value="${db.username}" />
<property name="password" value="${db.password}" /> <!-- Connection Pooling Info -->
<property name="initialPoolSize" value="1" />
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="15" />
<property name="maxIdleTime" value="1800" />
<property name="maxStatements" value="0" />
</bean> <bean id="jdbcTemplateDao" class="com.hzg.spring.jdbc.dao.JdbcTemplateDao" >
<property name="dataSource" ref="dataSource" />
</bean> <!-- JDBC事务管理器 -->
<bean id="jdbctTxManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean> <tx:advice id="txAdvice" transaction-manager="jdbctTxManager">
<tx:attributes>
<tx:method name="domain*"/>
      
</tx:attributes>
</tx:advice> <aop:config proxy-target-class="true">
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.chou.spring.jdbc.service.JdbcTemplateService.*(..))"/>
</aop:config>

DAO文件:

 public class JdbcTemplateDao extends JdbcDaoSupport{  

     public void save() {
String insertSql = "insert into tab_item values(?,?,?)";
Assert.isTrue(getJdbcTemplate().update(insertSql, new Object[]{6, "HP", "PT540"}) == 1, "插入失败");
} public void delete() {
String deleteSql = "delete tab_item where id = ?";
Assert.isTrue(getJdbcTemplate().update(deleteSql, new Object[]{6}) == 1, "删除失败");
} public void update() {
String updateSql = "update tab_item set itemno = ?, itemname = ? where id = ?";
Assert.isTrue(getJdbcTemplate().update(updateSql, new Object[]{"HP", "PT555", 6}) == 1, "修改失败");
}
}

service文件:

 @Service
public class JdbcTemplateService { @Autowired
private JdbcTemplateDao jdbcTemplateDao; public void domain(){
jdbcTemplateDao.save();
int i = 2/0;//这里出错了,事务就会回滚,之前的save就无效了
jdbcTemplateDao.update();
jdbcTemplateDao.delete();
}
}

Main方法

 //main方法
String[] configLocations = new String[] {"applicationContext.xml"};
ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations);
JdbcTemplateService j = ctx.getBean(JdbcTemplateService.class);
j.domain();

<tx:advice/>配置详解

 <tx:advice id="……" transaction-manager="……">
<tx:attributes>
<tx:method name="*"
propagation="REQUIRED"
isolation="DEFAULT"
timeout="-1"
read-only="true"
no-rollback-for=""
rollback-for="java.lang.Exception"/>
</tx:attributes>
</tx:advice> <!-- 最常用的配置 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="create*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="merge*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="put*" propagation="REQUIRED" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
<tx:method name="count*" propagation="SUPPORTS" read-only="true" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="list*" propagation="SUPPORTS" read-only="true" />
<tx:method name="*" propagation="SUPPORTS" read-only="true" />
<tx:method name="batchSaveOrUpdate" propagation="REQUIRES_NEW" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* cn.javass..service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
</aop:config>

XML形式的事务配置<tx:method >的属性详解

属性
类型
默认值
说明
propagation Propagation枚举 REQUIRED 事务传播属性
isolation isolation枚举 DEFAULT(所用数据库默认级别) 事务隔离级别
readOnly boolean false 是否才用优化的只读事务
timeout int -1 超时(秒)
rollbackFor Class[] {} 需要回滚的异常类
rollbackForClassName String[] {} 需要回滚的异常类名
noRollbackFor Class[] {} 不需要回滚的异常类
noRollbackForClassName String[] {} 不需要回滚的异常类名

readOnly 

事务属性中的readOnly标志表示对应的事务应该被最优化为只读事务。如果值为true就会告诉Spring我这个方法里面没有insert或者update,你只需要提供只读的数据库Connection就行了,这种执行效率会比read-write的Connection高,所以这是一个最优化提示。在一些情况下,一些事务策略能够起到显著的最优化效果,例如在使用Object/Relational映射工具(如:Hibernate或TopLink)时避免dirty checking(试图“刷新”)。

timeout 
在属性中还有定义“timeout”值的选项,指定事务超时为几秒。一般不会使用这个属性。在JTA中,这将被简单地传递到J2EE服务器的事务协调程序,并据此得到相应的解释。

Isolation Level(事务隔离等级)的5个枚举值 
1、DEFAULT:采用数据库默认隔离级别 
2、SERIALIZABLE:最严格的级别,事务串行执行,资源消耗最大; 
3、REPEATABLE_READ:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。 
4、READ_COMMITTED:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。 
5、READ_UNCOMMITTED:保证了读取过程中不会读取到非法数据。隔离级别在于处理多事务的并发问题。

propagation属性的7个传播行为 
1、REQUIRED:指定当前方法必需在事务环境中运行,如果当前有事务环境就加入此事务环境,如果没有就新建一个事务。(默认值) 
2、SUPPORTS:指定当前方法加入当前事务环境,如果当前没有事务,就以非事务方式执行。 
3、MANDATORY:指定当前方法必须加入当前事务环境,如果当前没有事务,就抛出异常。 
4、REQUIRES_NEW:指定当前方法总是发起一个新事务,存在别的事务就被挂起,直到我的事务方法commit结束,原先事务才恢复。 
5、NOT_SUPPORTED:指定当前方法以非事务方式执行,如果当前存在事务就挂起,等我以非事务的状态运行完,再继续原来事务。 
6、NEVER:指定当前方法绝对不能在事务范围内执行,如果方法在事务范围内执行,容器就抛异常,只有没关联到事务,才正常执行。 
7、NESTED:指定当前方法执行时,如果已经有一个事务存在,则运行在这个嵌套的事务中.如果当前环境没有运行的事务,就新建一个事务,并与父事务相互独立,这个事务拥有多个可以回滚的保证点。就是指我自己内部事务回滚不会对外部事务造成影响,只对DataSourceTransactionManager事务管理器起效。

Spring事务示例(注解形式@Transactional)

注意@Transactional只能被应用到public方法上,对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能。 
默认情况下,一个有事务的方法,遇到RuntiomeException时会回滚。遇到受检查的异常是不会回滚的,要想所有异常都回滚,要加上属性rollbackFor={Exception.class}

 <!-- 事务管理器配置 -->
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean> <!-- 使用annotation定义事务 -->
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />

transaction-manager:指定事务管理器名字,默认为transactionManager,当使用其他名字时需要明确指定; 
proxy-target-class:默认false表示使用JDK代理,如果为true将使用CGLIB代理 
order:定义事务通知顺序,默认Ordered.LOWEST_PRECEDENCE,表示将顺序决定权交给AOP来处理。

 @Transactional//放在这里表示所有方法都加入事务管理
public class AnnotationUserServiceImpl implements IUserService {
private IUserDao userDao;
private IAddressService addressService; @Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITTED)
public void save(UserModel user) {
userDao.save(user);
user.getAddress().setUserId(user.getId());
addressService.save(user.getAddress());
} @Transactional(propagation=Propagation.REQUIRED, readOnly=true,
isolation=Isolation.READ_COMMITTED)
public int countAll() {
return userDao.countAll();
}
//setter...
}

-----------------------------------------------------------------------------------------------------------------------

跟着刚哥学习Spring框架--创建HelloWorld项目(一)

跟着刚哥学习Spring框架--Spring容器(二)

跟着刚哥学习Spring框架--通过XML方式配置Bean(三)

跟着刚哥学习Spring框架--通过注解方式配置Bean(四)

跟着刚哥学习Spring框架--AOP(五)

跟着刚哥学习Spring框架--JDBC(六)

跟着刚哥学习Spring框架--事务配置(七)

跟着刚哥学习Spring框架--事务配置(七)的更多相关文章

  1. 跟着刚哥学习Spring框架--通过注解方式配置Bean(四)

    组件扫描:Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件. 特定组件包括: 1.@Component:基本注解,识别一个受Spring管理的组件 2.@Resposit ...

  2. 跟着刚哥学习Spring框架--通过XML方式配置Bean(三)

    Spring配置Bean有两种形式(XML和注解) 今天我们学习通过XML方式配置Bean 1. Bean的配置方式 通过全类名(反射)的方式   √ id:标识容器中的bean.id唯一. √ cl ...

  3. 跟着刚哥学习Spring框架--创建HelloWorld项目(一)

    1.Spring框架简介 Spring是一个开源框架,Spring是在2003年兴起的一个轻量级的开源框架,由Rod johnson创建.主要对JavaBean的生命周期进行管理的轻量级框架,Spri ...

  4. 跟着刚哥学习Spring框架--AOP(五)

    AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入 ...

  5. 跟着刚哥学习Spring框架--Spring容器(二)

    Spring容器 启动Spring容器(实例化容器) -- IOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化(加载启动),这样才可以从容器中获取Bean的实例并使用.  Bean是S ...

  6. 跟着刚哥学习Spring框架--JDBC(六)

    Spring的JDBC框架 Spring JDBC提供了一套JDBC抽象框架,用于简化JDBC开发. Spring主要提供JDBC模板方式.关系数据库对象化方式.SimpleJdbc方式.事务管理来简 ...

  7. 跟着刚哥梳理java知识点——数组(七)

    数组:数组是多个相同类型数据类型的集合,实现对这些数据的统一管理. 元素:数组中的元素可以是任何数据类型,包括基本数据类型和引用类型. 特点:属于引用类型,数组型数据是对象object,数组中的每个元 ...

  8. 深入浅出学习Spring框架(四):IoC和AOP的应用——事务配置

    在前文 深入浅出学习Spring框架(一):通过Demo阐述IoC和DI的优势所在. 深入浅出学习Spring框架(三):AOP 详解 分别介绍了Spring的核心功能——IoC和AOP,光讲知识远远 ...

  9. spring 实现事务配置的方式

    spring 中常用的两种事务配置方式以及事务的传播性.隔离级别 一.注解式事务 1.注解式事务在平时的开发中使用的挺多,工作的两个公司中看到很多项目使用了这种方式,下面看看具体的配置demo. 2. ...

随机推荐

  1. 检索 COM 类工厂中 CLSID 为 {10021F00-E260-11CF-AE68-00AA004A34D5} 的组件失败,原因是出现以下错误: 80040154 没有注册类 (异常来自 HRESULT:0x80040154 (REGDB_E_CLASSNOTREG))。

    ASP.NET利用SQLDMO可以实现在线备份.还原数据库等各种功能. 由于客户的数据库和WEB服务不再同一台服务器,把网站部署在服务器上以后,运行程序,提示如下错误 当使用Interop.SQLDM ...

  2. c#中委托与事件

    参考:http://www.tracefact.net/tech/009.html 张子阳:http://www.cnblogs.com/JimmyZhang/archive/2007/09/23/9 ...

  3. Java潜在的坑持续总结

    1.Java里如果有if (foo == 0),如果foo是null这里居然是会抛NPE异常而不是返回false: 2.Java里整形数值不能用==来比较,因为只有区间是[-128,127]的才能这么 ...

  4. user表中存在多条相同user不同host用户信息时MySQL该匹配哪条记录登录?

    问题: 当用户名相同,但主机名不同的多条记录.用户由不同主机登录时,选择使用那条记录来验证,数据库版本为:5.6.25 如:IP为192.168.141.241 hostname为vhost02主机上 ...

  5. 如何使用vs进行代码比较

    当我们在进行团队合作开始项目时,有时候不仅自己要写代码还需要修改bug,当我们修改代码以后,为了保持代码库中代码的整洁美观和一直性,有些误操作,比如多一个或多个空格,多一行,少一行,格式对齐等,这样的 ...

  6. HTTP 错误 500.XX - Internal Server Error 解决办法

    HTTP 错误 500.19 - Internal Server Error 无法访问请求的页面,因为该页的相关配置数据无效. 详细错误信息 模块 IIS Web Core 通知 未知 处理程序 尚未 ...

  7. 通用的进程监控脚本process_monitor.sh使用方法

    不用做任何修改,即可用process_monitor.sh监控各种进程. 源码下载:https://github.com/eyjian/libmooon/blob/master/shell/proce ...

  8. SpringMVC(一)helloWorld

    web.xml文件配置如下: <?xml version="1.0" encoding="UTF-8"?> <web-app version= ...

  9. Video Processing and Communications:(视频处理和通信)

    https://max.book118.com/html/2017/1010/136711526.shtm Application of (GAN) of AI faceswap in Music V ...

  10. 个人理解的int数组和char数组

    char数组中不论是一维还是二维的,在程序执行时每一块的分离依据都是以提供的起始地址到'\0'为一个处理的字符串.所以关于char[]的函数都是只提供相应起始地址作为形参就可以. char[]互相交换 ...