一、maven配置
加入aop配置即可:
<!--aop --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.9.6</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.6</version> </dependency>
二、配置文件applicationContext.xml中的配置
主要配置事务管理器、附加代码和切面
好处就是不用手动创建类进行事务管理,不然还需要创建一个aop的interceptor
<?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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--引用db.properties文件的内容--> <context:property-placeholder location="db.properties"/> <!-- 配置数据源(Druid) --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <!-- <bean id="dataSource" class="org.apache.ibatis.datasource.pooled.PooledDataSource">--> <!-- <property name="driver" value="${driverClass}"/>--> <property name="driverClassName" value="${driverClass}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </bean> <!-- 创建SqlSessionFactory--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--数据源--> <property name="dataSource" ref="dataSource"/> <!--设置别名,这个包里面的类会自动设置别名--> <property name="typeAliasesPackage" value="com.mj.domain"/> <!--mybatis文件映射文件的位置--> <property name="mapperLocations"> <list> <value>mappers/*.xml</value> </list> </property> </bean> <!--扫描Dao--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--SqlSessionFactoryBean的id--> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <!--dao的包名--> <property name="basePackage" value="com.mj.dao"/> </bean> <bean id="skillService" class="com.mj.service.impl.SkillServiceImpl"> <property name="dao" ref="skillDao"/> </bean> <!--事物管理器--> <bean id="txMgr" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--附加代码,不需要导入手动创建的bean,事物管理代码--> <tx:advice id="txAdvice" transaction-manager="txMgr"> <tx:attributes> <!--明确说明这里方法需要管理事务,*代表通配符以list开头的方法--> <!--propagation:REQUIRED 是默认管理事务,支持当前事务,如果没有事务开启新事物,一般增,删,改用--> <!--propagation:SUPPORTS 支持当前事务,当前无事物也不开启新事务,一般用来查询--> <!--propagation;REQUIRES_NEW当前有事务,则挂起当前事务开启新事务,当前没有事务则开启新事务,一般用日志记录--> <!--rollback-for:Exception 代表所有的异常都进行事务回滚,默认情况下,RuntimeException\Error会导致事务回滚,而Exception不会回滚事务--> <tx:method name="list*" propagation="SUPPORTS" rollback-for="Exception"/> <tx:method name="save" propagation="REQUIRED"/> <tx:method name="update" propagation="REQUIRED"/> <tx:method name="test" propagation="REQUIRES_NEW"/> </tx:attributes> </tx:advice> <!--切面--> <aop:config> <aop:pointcut id="pc" expression="within(com.mj.service..*)"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/> </aop:config> </beans>
三、impl实现类
package com.mj.service.impl;
import com.mj.dao.SkillDao;
import com.mj.domain.Skill;
import com.mj.service.SkillService;
import java.util.List;
public class SkillServiceImpl implements SkillService {
private SkillDao dao;
public void setDao(SkillDao dao) {
this.dao = dao;
}
public List<Skill> list() {
return dao.list();
}
public boolean save(Skill skill) {
return dao.save(skill);
}
public boolean update(Skill skill) {
return dao.update(skill);
}
public void test() {
Skill skill = new Skill("777",777);
skill.setId(2);
dao.update(skill);
System.out.println(10/0);
dao.save(new Skill("888",888));
}
}
四、测试类代码:
public class SkillTest {
private static final ApplicationContext ctx;
private static SkillService skillService;
static {
ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
skillService = ctx.getBean("skillService", SkillService.class);
}
@Test
public void list() {
List<Skill> skills = skillService.list();
System.out.println(skills);
}
@Test
public void update(){
Skill skill = new Skill();
skill.setName("我是大洲洲");
skill.setLevel(5);
skill.setId(2);
skillService.update(skill);
}
@Test
public void save() {
Skill skill = new Skill();
skill.setName("我是大洲洲");
skill.setLevel(5);
skillService.save(skill);
}
@Test
public void test() {
skillService.test();
}
}
五、事务的隔离级别
- 如果多个事务同时操作同一份数据,可能引发以下问题
- 脏读:一个事务读取到了另一个事务没有提交的数据
- 不可重复读:一个事务范围内两个相同的查询却返回了不同的数据
- 幻读:一个事务发现了之前本来确认不存在的数据
- 可以设置隔离级别来解决上述问题(由上到下,性能依次降低)
- READ UNCOMMITTED:什么也解决不了
- READ COMITED:可以防止脏读
- REPEATABLE READ:可以防止脏读和不可重复读(MySQL的默认隔离级别)
- SERLALIZBLE:可以防止脏读、不可重复读、幻读