第2章 Spring编程式事务

2-1 编程式事务-1

什么是事务?

 对于spring jdbc我们如何进行事务控制呢?

 

 通过实际的代码学习如何事务管理器完成实物的提交或者回滚

公司入职10名新员工,将员工批量的导入员工表中,唯一的要求就是一次全部导入成功,要么什么都不做。

创建service包 业务逻辑

 

批量导入方法

 

 

 配置,完成注入

 测试方法

植入service

 调用

 

 

 

 这里觉得程序写完了就大错特错了,因为对于这10个数据来说他们并不是在一个事务中完成的

为什么这么说打印下日志看一下

加入依赖

 先删除增加的数据,重新执行

 都是更新操作

 从数据源获取jdbc数据连接

 创建全新的连接

 在新的连接中去执行sql语句

 这一部分是完成了一条数据的新增部分

 每执行一次循环都会重复的产生这个日志

这就意味着,在刚才循环的过程中,顶层并不是使用一个数据库连接而是创建了10个数据库链接,完成了十次插入的操作,同时也进行了10次提交。这十条数据在各自的事务中并不是一个整体,我们期望的正确结果是这10次insert操作应该是在1个数据库连接中重复的去执行insert

 

 

 我们的需求是 10条必须全部插入成功如果出现问题就什么都不做

如何解决?那就是引入事务进行整体判断

2-2 编程式事务-2

使用程序代码是手动控制什么时候提交?什么时候回滚?

编程式事务需要配置一个核心的对象

事务管理器

基于数据源的管理器,需要绑定一个数据源

 基于这个管理器就能完成对事物的整体提交和回滚

怎么用?

注入他 

 生成getset

回到xml的service中对他进行注入

 此时就具备的事务管理功能

 从这句以后所有数据的新增修改删除都会被直接放到事务区中由事务统一进行管理

 事务状态包含了当前方法所执行事务的目前阶段

成功

 出现错误要进行捕捉,进行回滚,将运行时异常原封不动的抛出去

运行

 

 抛出异常意味着要在事务中进行回滚

 部分数据不再出现

底层原理

 第二次循环并没有创建新的数据库连接,而是去应用原有的唯一的数据库连接

 第三次出现异常的时候 回滚

 增加后所有的数据库连接都是在一个中完成的,写入的数据并不是直接进入表中而是放到了事务区中,之后再根据方法是否执行成功,来提交或者回滚

 

 

 

频繁地使用去完成数据的新增

 

 

完成10次后 一次性提交写入

3-1 声明式事务配置

 编程式事务根据么个程序员的水平不同可能会出现遗忘事务控制的状况

 

 

 

代码演示, 打开s02基础工程

不修改原始代码的情况下配置声明式事务

引入依赖

 事务管理器

事务通知配置

额外增加一个命名空间url地址

 增加所对应描述文件xsd的地址

 aop命名空间

aop的xsd地址

 

 说明事务通知作用在那些类上要确定通知范围

 测试运行

 

 

 

 

 成功

 又有一个新问题现在只有一个bacthImport,但是未来service上有各种各样的方法,难道要在

 定义成百上千个方法说明他是声明式事务吗其实不用

可以进行通配符映射batchImport可以写成

 不需要事务和写操作的方法

 与之类似的

其它选项,当前面几项都不符合要求时其他的情况是否开启声明式事务?

默认使用

 

不适用,根据情况而定

 

 3-2 自由编程

 答案

package com.imooc.spring.jdbc.dao;
 
import com.imooc.spring.jdbc.entity.Hotel;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
 
import java.util.List;
 
public class HotelDao {
   private JdbcTemplate jdbcTemplate;
   public Hotel findById(Integer OrderNo){
       String sql="select* from hotel where OrderNo=?";
       Hotel hotel = jdbcTemplate.queryForObject(sql, new Object[]{OrderNo}, new BeanPropertyRowMapper<Hotel>(Hotel.class));
       return hotel;
 
   }
   public List<Hotel>  findByCity(String city){
       String sql="select * from hotel where city=?";
       List<Hotel> list = jdbcTemplate.query(sql, new Object[]{city}, new BeanPropertyRowMapper<Hotel>(Hotel.class));
       return list;
 
   }
   public int insert(Hotel hotel){
       String sql="insert into hotel(orderNo,city,price,hotelName,arriveDate,leaveDate)values(?,?,?,?,?,?)";
       int i = jdbcTemplate.update(sql, new Object[]{hotel.getOrderNo(), hotel.getCity(), hotel.getPrice(), hotel.getHotelName(), hotel.getArriveDate(), hotel.getLeaveDate()});
 
       return i;
   }
   public int alter(Hotel hotel){
       String sql="update hotel set city=?,price=?,hotelName=?,arriveDate=?,leaveDate=? where orderNO=? ";
       int count = jdbcTemplate.update(sql, new Object[]{hotel.getCity(), hotel.getPrice(), hotel.getHotelName(),hotel.getArriveDate(), hotel.getLeaveDate(),hotel.getOrderNo()});
       return count;
   }
   public  int delete(Integer integer){
       String sql="delete from hotel where orderNo=?";
       int count = jdbcTemplate.update(sql, new Object[]{integer});
       return count;
 
   }
 
 
    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }
 
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
}
package com.imooc.spring.jdbc.entity;
 
import java.util.Date;
 
public class Hotel {
    private Integer orderNo;
    private String city;
    private Float price;
    private String hotelName;
    private Date arriveDate;
    private Date leaveDate;
 
    @Override
    public String toString() {
        return "Hotel{" +
                "orderNo=" + orderNo +
                ", city='" + city + '\'' +
                ", price=" + price +
                ", hotelName='" + hotelName + '\'' +
                ", arriveDate=" + arriveDate +
                ", leaveDate=" + leaveDate +
                '}';
    }
 
    public Integer getOrderNo() {
        return orderNo;
    }
 
    public void setOrderNo(Integer orderNo) {
        this.orderNo = orderNo;
    }
 
    public String getCity() {
        return city;
    }
 
    public void setCity(String city) {
        this.city = city;
    }
 
    public Float getPrice() {
        return price;
    }
 
    public void setPrice(Float price) {
        this.price = price;
    }
 
    public String getHotelName() {
        return hotelName;
    }
 
    public void setHotelName(String hotelName) {
        this.hotelName = hotelName;
    }
 
    public Date getArriveDate() {
        return arriveDate;
    }
 
    public void setArriveDate(Date arriveDate) {
        this.arriveDate = arriveDate;
    }
 
    public Date getLeaveDate() {
        return leaveDate;
    }
 
    public void setLeaveDate(Date leaveDate) {
        this.leaveDate = leaveDate;
    }
}
package com.imooc.spring.jdbc.service;
 
import com.imooc.spring.jdbc.dao.HotelDao;
import com.imooc.spring.jdbc.entity.Hotel;
 
import java.util.Date;
 
public class HotelService {
    private HotelDao hotelDao;
    public  void batchImport(){
     for (int i=1;i<=5;i++){
         if (i==3){
             throw new RuntimeException();
         }
         Hotel hotel=new Hotel();
         hotel.setOrderNo(100+i);
         hotel.setCity("长沙");
         hotel.setHotelName("酒店8"+i);
         hotel.setArriveDate(new Date());
         hotel.setLeaveDate(new Date());
         hotel.setPrice(999.98f+i);
         hotelDao.insert(hotel);
     }
    }
 
    public HotelDao getHotelDao() {
        return hotelDao;
    }
 
    public void setHotelDao(HotelDao hotelDao) {
        this.hotelDao = hotelDao;
    }
}
<?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:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans https://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/tx https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
 
    <!-- bean definitions here -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/jdbc_imooc?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true">
    </property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
</bean>
    <bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <tx:advice id="txAdvice" transaction-manager="transactionManger">
        <tx:attributes>
            <tx:method name="batchImport" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(public * com.imooc..*Service.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"></aop:advisor>
    </aop:config>
    <bean id="hotelDao" class="com.imooc.spring.jdbc.dao.HotelDao">
<property name="jdbcTemplate" ref="JdbcTemplate"></property>
    </bean>
    <bean id="transactionManger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource">
        </property>
    </bean>
    <bean id="hotelService" class="com.imooc.spring.jdbc.service.HotelService">
        <property name="hotelDao" ref="hotelDao">
 
        </property>
    </bean>
</beans>
import com.imooc.spring.jdbc.dao.HotelDao;
import com.imooc.spring.jdbc.entity.Hotel;
import com.imooc.spring.jdbc.service.HotelService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
 
import java.util.Date;
import java.util.List;
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:applicationContext.xml"})
public class JdbcTemplateTestor {
    @Resource
    private HotelService hotelService;
    @Resource
    private HotelDao hotelDao;
    @Test
    public void testFindById(){
        Hotel hotel = hotelDao.findById(10001);
        System.out.println(hotel);
 
    }
    @Test
    public void testFindByName(){
        List<Hotel> 上海 = hotelDao.findByCity("上海");
        System.out.println(上海);
 
    }
    @Test
    public  void testInsert(){
        Hotel hotel=new Hotel();
        hotel.setOrderNo(10099);
        hotel.setCity("长沙");
        hotel.setHotelName("酒店8");
        hotel.setArriveDate(new Date());
        hotel.setLeaveDate(new Date());
        hotel.setPrice(999.98f);
        int count = hotelDao.insert(hotel);
        System.out.println(count);
    }
    @Test
    public void testUpdate() throws ParseException {
        String date1="2020-4-30";
        String data2="2020-5-05";
        SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyy-MM-dd");
        Hotel hotel = hotelDao.findById(10003);
        hotel.setLeaveDate(simpleDateFormat.parse(date1));
        hotel.setArriveDate(simpleDateFormat.parse(data2));
        int count = hotelDao.alter(hotel);
        System.out.println(count);
    }
    @Test
    public  void testDelete(){
        int count = hotelDao.delete(10099);
        System.out.println(count);
    }
    @Test
    public  void testBatchImport(){
        hotelService.batchImport();
        System.out.println("批量插入成功");
 
    }
    }

3-3 事务传播方式

 

 通过案例了解

 propagation会为我们带来那些特性

还需要开发大量类似于batchimport的方法怎么办呢?

 

依赖于

 

 

 

 新增一个方法

 增加bean

 

 

 

 测试

 插入成功

 作为当前代码是事物的嵌套使用

 默认也是开启声明式事务的

 

 当前的配置是有问题的

作为批量导入,这两个方法之间应该是互不影响的但是employeeservice却做不到这个职责

演示一下

 

数据没有插入成功

import1插入成功就应该插入,但实际结果却不是这样

 

 startImportJob在运行时会创造一个事物,而内侧嵌套调用的importjob1和importjob2因为配置的也是required内测执行时发现外侧已经有现成的事务了,所以job1的事务就会加入到外侧事务当中,也就是说整体是在一个事务中完成数据的增删改操作

 要是这两个方法相对于start方法独立该怎么做呢?

 针对这两个方法在运行的过程中都会产生新的事务来自进行处理

更改后执行

 

 数据就产生了

 

 

 3-4 选择练习

 

 

 3-5注解形式声明事务

 注解改造

设置扫描的基本包

 定义数据源

 针对系统底层公用类还是要自己增加bean来进行实例化

还要定义事务管理器 

 注解来完成对象实例化

 完成对象的注入

 

 测试一下

 

 

 下面把关注点放在事务控制上,作为声明式事务如果利用注解非常的简单,全程只有一个注解

 测试

 事务被成功地回滚了

 对应于不同的方法也可以单独设置

在这个查询方法上去应用声明式事务是无效的

进行单独设置采用非事务方式

 那么会优先利用这个方式其他的方法默认使用在类上的配置

 针对batchservice来进行一下设置,import方法都是可以独立的在方法中运行

 

 在方法上也可以设置默认值,不需要使用事务 

 测试,能否将前半部分成功的导入 

 

 

 3-6 自由编程

猜你喜欢

转载自blog.csdn.net/lonelyneet/article/details/125927524