基于XML配置的声明式事务控制[重点]
开发步骤
- 添加Spring事务需要的jar包依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
</dependencies>
主配置文件代码
<!--组件扫描 扫描报下所有类让他的类自动加载进入我们的Spring容器中。-->
<context:component-scan base-package="com.zhiyou100"></context:component-scan>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db_spring"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启Spring支持事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
pojo实体类
//@Component("user") 这里注释的原因是因为xml主配置文件里面使用到了组件扫描,这里就可以不用书写了
public class User implements Serializable {
private Integer u_id;
private String u_name;
private Integer u_age;
private Double u_salary;
userDao接口和他的实现类
public interface UserDao {
// 查询单个用户 根据id值
User queryUserById(int uid);
// 根据用户名称查询用户信息
User findUserByUsername(String username);
void updateUserByUsername(User descUser);
}
//dao接口实现类
@Repository("userDao") //把数据放到Spring空间里面
public class UserDaoImpl implements UserDao {
@Autowired //把空间里面的对象通过属性注入
private JdbcTemplate jdbcTemplate;
@Override
public User queryUserById(int uid) {
// 根据用户id值查询一条记录 queryForObject方法
User user = null;
try {
user = jdbcTemplate.queryForObject("select * from user where u_id = ?", new BeanPropertyRowMapper<>(User.class), uid);
}catch (Exception e) {
e.printStackTrace();
}
return user;
}
@Override
public User findUserByUsername(String username) {
// 根据用户id值查询一条记录 queryForObject方法
User user = null;
try {
user = jdbcTemplate.queryForObject("select * from user where u_name = ?", new BeanPropertyRowMapper<>(User.class), username);
}catch (Exception e) {
e.printStackTrace();
}
return user;
}
@Override
public void updateUserByUsername(User descUser) {
jdbcTemplate.update("update user set u_salary = ? where u_name = ?", descUser.getU_salary(),descUser.getU_name());
}
Service层和Service接口
// 业务层接口
public interface UserService {
// 准备两个方法
// 根据id值查找用户信息
User findUserById(int uid);// 查 读的动作 readOnly--->true
// 工资变更 把一个人工资的降一降 把另一个工资升一升
boolean changeSalary(String descUsername ,String ascUsername,double money);// 修改 写的动作 readOnly--->false
}
//Service接口实现类
@Service("userService")// 把UserServiceImpl类对象交给Spring管理
@Transactional(propagation = Propagation.REQUIRED,readOnly = true,isolation = Isolation.DEFAULT) //该类的所有 public 方法将都具有该类型的事务属性,
public class UserServiceImpl implements UserService {
// 属性注入
@Autowired //属性注入,以为我们之前已经把这个为对象放在了Spring空间中
private UserDao userDao;
@Override
public User findUserById(int uid) {
User user = userDao.queryUserById(uid);// 根据uid查询用户信息
return user;
}
@Transactional(propagation = Propagation.REQUIRED,readOnly = false)
@Override
public boolean changeSalary(String descUsername, String ascUsername, double money) {
User descUser = userDao.findUserByUsername(descUsername);
descUser.setU_salary(descUser.getU_salary() - money);
// 在当前工资的基础上加
User ascUser = userDao.findUserByUsername(ascUsername);
ascUser.setU_salary(ascUser.getU_salary() + money);
try {
userDao.updateUserByUsername(descUser);
int i = 1 / 0; // 算术异常
userDao.updateUserByUsername(ascUser);
}catch (Exception e){
// 当事务中出现异常 使用手动回滚。
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return true;
}
}
测试类代码
@RunWith(SpringJUnit4ClassRunner.class)//使得拥有测试类作用
@ContextConfiguration("classpath:applicationContext.xml")//匹配主配置问价,使得能更好的操作内部的属性
public class JdbcTemplateTest {
@Autowired
private UserService userService;
/**
* 测试 工资变更的事务
*/
@Test
public void testChangSalary() {
// 1000
boolean flag = userService.changeSalary("李四", "张三", 1000);
System.out.println(flag);
}
}
备注:
把可能出现异常的代码放进try catch语句块中。
当事务中出现异常,使用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
进行手动回滚
当用try-catch包括dao层接口,如果有异常数据无法完成回滚因为我们把异常捕获了,所以spring事务就不回滚