事务处理
什么是事务
事务是指一组sql语句的集合,集合中有多条sql语句肯能是insert、update、select,我们希望这些所有的sql语句都成功,或者都失败。属于数据库的特性。
事务的四大特性:
原子性、隔离性、持久性、一致性
事务的作用
保证用户的每一个操作都是可靠的,事务中的每一步操作都必须成功执行,只要有发生异常就回退到事务开始未进行操作的状态,这些操作要么都完成,要么都取消,从而保证数据满足一致性的要求 。
什么时候用到事务
当操作涉及多个表,或者多个sql语句的insert、update、select,需要保证这些语句都是成功或者都失败。例如:转账,A账户给B账户转账,如果转账成功,则A账户的资金需要减少,B账户资金需要增加,如果不成功,则两边的资金都不变。
spring事务管理
spring事务管理,指的是spring框架提供了对事物进行提交,回滚的功能,帮助进行事物管理
Spring 中的事务管理分为两种形式,一种是编程式事务,一种是声明式事务.
编 程 式 事 务 在 项 目 中 很 少 使 用 , 这 种 方 式 需 要 注 入 一 个 事 务 管 理 对 象TransactionTemplate ,然后在我们代码中需要提交事务或回滚事务时自己写代码实现。
声明式事务管理建立在 AOP 基础上,本质是对方法前后进行拦截,所以声明式事务是方法级别的。
Spring 声明式事物管理方式有两种:
- 基于 xml 配置
- 基于注解实现
配置事务管理器
<!--配置spring事务管理,并注入数据源-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
注解方式
<!--开启注解事务管理-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
-->
在service中控制事务
@Service(“adminService”)
@Transactional:可以作用在类和方法上,加载类上,表示类中所有的方法都接受事务
失效情况
- @Transactional 应用在非 public 修饰的方法上
- 异常被 catch 捕获导致失效 (底层建议抛出,不做处理)
- 出现编译期异常 ,默认情况下只对运行期异常进行捕获,但是是可以修改的
//默认情况下
@Transactional(rollbackFor = RuntimeException.class)
//自定义
@Transactional(rollbackFor = Exception.class)
- @Transactional 事务传播行为设置错误
- 数据库引擎不支持事务 查询多使用MyISM引擎,对增删改查使用InnoDB引擎支持事务
- 同一个类中,使用非代理对象调用一个有事务的方法,导致事务错误
public void zz() throws UnsupportedEncodingException {
this.zhuanZhang();
}
@Transactional(rollbackFor = Exception.class)
public void zhuanZhang() throws UnsupportedEncodingException {
adminDao.sub();
System.out.println("ah".getBytes("utf-9"));
adminDao.add();
}
//在非事务方法中,通过this调用事务方法
Spring事务传播行为
传播:方法的相互调用。
事务传播行为指的是当一个事务方法被另一个事务方法调用,这个事务方法应该如何进行。例如:methodA 事务方法调用 methodB 事务方法时,methodB 是继续在调用者 methodA 的事务中运行呢,还是为自己开启一个新事务运行,这就是由methodB 的事务传播行为决定的。事务传播行为是 Spring 框架独有的事务增强特性,与数据库无关。
Spring 定义了七种传播行为:
- PROPAGATION_REQUIRED
指定的方法必须在事务内执行,若当前存在事务,加入到当前事务中,若当前没
有事务,则创建一个新事务,这种传播行为是最常见的,也是 spring 默认的传播行
为。
- PROPAGATION_SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行。当一个有事务的方法,调用了传播行为 SUPPORTS,那么被调用的方法合并到当前事务中;当一个没有事务的方法,调用了传播行为 SUPPORTS,那么被调用的方法也就没有事务了。
- PROPAGATION_REQUIRES_NEW
总是新建一个事务,如果当前存在事务,把当前事务挂起,直到新建的事务结束。
Spring集成Mybatis
Spring 集成 Mybatis 其核心是将 SqlSessionFactory 交由 Spring 管理,并由Spring 管理对 dao 接口的代理实现。
- 导入mybatis jar包
<!--spring结合mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
-
添加spring-mybatis.xml文件
-
在spring-mybatis.xml文件中配置 sqlSessionFactory
<!--配置 sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:mybatisConfig.xml"></property>
<property name="mapperLocations" value="classpath:mapper/*Mapper.xml"> </property>
</bean>
- 在spring-mybatis.xml文件中导入数据库配置文件,注入数据源
因为sqlSessionFactory需要使用数据库,数据库在前面jdbc已经配置过,只需要导入db.xml文件即可。
<import resource="classpath:db.xml"></import>
- 导入Mybatis配置文件
之前在mybatis中的配置文件可以直接赋值过来,稍作改善。只剩下settings和typeAliases两个标签。需要修改别名标签中的路径。
- 指定生成接口代理,需要改basePackage中的路径。
<!--指定生成接口代理-->
<bean id="mapperFactory" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.ffyc.ssm.dao"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"> </property>
</bean>
-
创建实体类、对应接口以及映射文件
-
测试
public interface StudentDao {
Student findStudent(int id);
}
<select id="findStudent" resultType="com.ffyc.ssm.model.Student">
select id,name,gender from student where id=#{id};
</select>
@Service("studentService")
public class StudentService {
@Autowired
StudentDao studentDao;
public Student findStudent(int id){
return studentDao.findStudent(id);
}
}
public void test(){
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentService studentService = (StudentService) app.getBean("studentService");
Student a = studentService.findStudent(2);
System.out.println(a);
}