程序员社区

Spring入门后半部分----JDBCTemplate和事务控制

JDBCTemplate和事物控制

  • JDBCTemplate基本使用,承接上半部分
    • 抽取数据库连接池配置时填入的参数,放到properties配置文件中
    • 在Spring容器中引入pro配置文件,然后修改刚才传入的参数—配置数据库的模板
      • 注意: ${}取出配置文件中的值 ,#{}是Spring的表达式语言
    • 在主类中向数据库插入数据
      • 批量插入的方法
    • 查询某条记录,封装为一个java对象,并返回
      • JavaBean对象的属性名需要和数据库中的字段名一致,否则无法完成数据的封装,当前也可以在编写查询sql语句的时候,通过对数据库每列的名称起一个别名,来达到封装的目的
      • 这里的属性名依旧是set方法,去掉set,首字母小写得到的字符串,因此set方法必不可少
      • jdbcTemplate在方法级别进行了区分: 查询集合,查询单个对象
    • 查询集合
    • 查询单条数据
    • 使用带有具名参数的sql语句插入一条员工记录,并以Map的形式传入参数值
      • 以map的形式传入参数
      • 以SqlParameterSource的形式传入参数
        • 使用该方法前,要确保自定义类中有get方法,因为该方法实现原理是从传入的对象中,找对象的get方法,去掉get,首字母小写,看得到的字符串是否和具名参数匹配.
      • 使用注解完成对JdbcTemplate的注入----小规模常用
  • 声明式事务
    • 数据库环境搭建---账户表,图书表,图书库存表
    • jdbc.properties的配置文件
    • 数据源配置并直接注入到jdbcTemplate中
    • Dao层和Service层的类环境搭建
  • 声明式事务
    • 事务管理器(事务切面)
      • 第一步:配置事务管理器,让其进行事务控制
      • 第二步: 开启基于注解的事务控制模式,依赖tx命名空间
      • 第三步:给事务方法加上注解即可
      • 加上注解之后,如果事务方法里面出现异常,那么整个事务方法会进行回滚,数据恢复原样
    • @Transactional注解里面的属性分析
      • timeout---->参数值为int(秒为单位),超时,事务超出指定执行时长后自动终止并回滚
      • readOnly---->参数值为bool,设置事务为只读,可以进行事务优化,默认readOnly=false,改为readOnly=true后,可以加快查询速度,因此不用管事务的相关操作了(设置自动提交....)
      • 如果事务方法中有增删改相关操作,还设置为true时,运行时会报错
      • 异常分类
      • noRollbackFor---->参数值为Class[] (字节码文件类型,是个数组) ,那些异常事务可以不回滚
      • noRollbackForClassName---->参数值为String[] (全类名) ,那些异常事务可以不回滚
      • rollbackFor---->参数值为Class[] (字节码文件类型) ,哪些异常事务需要回滚
      • rollbackForClassName---->参数值为String[] (全类名),哪些异常事务需要回滚
      • ioslation调整隔离级别
        • 前置知识:数据库事务并发问题
        • 同时对一个数据进行修改(并发修改同一个数据下的排队,挨个按照顺序进行修改操作)
        • 前置知识:隔离级别
        • 前置知识:查询mysql的隔离级别
        • 前置知识:事务操作
        • 前置知识:修改mysql的隔离级别
        • 有事务的业务逻辑,容器中保存的是这个业务逻辑的代理对象(了解即可)
    • 事务传播行为(事务的传播和事务的行为)
      • 简单理解: 一个事务相等于一辆车,如果子事务和大事务共同用一个事务,那么可以理解为子事务和大事务位于同一辆车上。如果子事务开启一个新事务,相当于子事务开了一辆新车,大事务和子事务位于不同的车上面
      • 注意: 出现的异常回一层一层往上面进行传递,坐一辆车的全崩,开新车并且在异常之前执行的不崩;开新车,但是位于异常之后,崩。
      • 注意:如果子事务出现了异常,并且子事务位于大事务的方法体内部,那么大事务会感受到异常,那么即便大事务和子事务开不同的车,大事务也会崩掉,因为方法体内部出现了异常
      • 子事务只和上一级的事务坐一辆车,不会和上一级的上一级的事务坐一辆车,除非他的上一级的事务和他的上一级的上一级的事务坐一辆车
      • 总结图
      • 设置事务传播行为演示
      • 重点:REQUIRED事务属性来源于大事务(子事务和大事务坐一辆车时),即子事务的所有属性,例如超时设置,回滚设置,都继承于大事务,即使子事务里面设置了,也没有用
      • propagation = Propagation.REQUIRES_NEW可以调整,默认是REQUIRED
      • REQUIRED将之前事务使用的connection传递给这个事务使用
      • REQUIRED_NEW这个方法直接使用新的connection
      • 本类事务方法之间的调用就只是一个事务
      • 在本类中给本类对象进行注入,会造成死循环
    • 事务控制的xml配置:依赖tx名称空间和aop名称空间
    • 要导入spring-tx坐标,spring处理事务相关的坐标
    • 切点方法事务配置参数
      • 1.引入依赖
      • 2.开启注解扫描---引入context命名空间
      • 3.引入properties配置文件
      • 4.创建数据源dataSource
      • 5.创建JdbcTemplate对象
      • 6.创建事务管理器对象: 增强(通知)
      • 7.事务增强:对方法的过滤
      • 8.配置aop

Spring入门前半部分

JDBCTemplate基本使用,承接上半部分

抽取数据库连接池配置时填入的参数,放到properties配置文件中

properties配置文件:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test1
jdbc.username=root
jdbc.password=126433

在Spring容器中引入pro配置文件,然后修改刚才传入的参数—配置数据库的模板

注意: ${}取出配置文件中的值 ,#{}是Spring的表达式语言

    <!--加载jdbc.properties-->
<!--引入context命名空间-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!--数据源对象-->
     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
         <property name="driverClass" value="${jdbc.driver}"/>
         <property name="jdbcUrl" value="${jdbc.url}"/>
         <property name="user" value="${jdbc.username}"/>
         <property name="password" value="${jdbc.password}"/>
     </bean>
   <!--jdbc模板对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
    </bean>

在主类中向数据库插入数据

public class jdbc {
    public static void main(String[] args) {
        ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
        JdbcTemplate jt = app.getBean(JdbcTemplate.class);
        int row = jt.update("insert account values (?,?),(?,?)", "大忽悠", 8000, "小朋友", 6000);
        System.out.println("影响的行数"+row);
    }
}

批量插入的方法

        ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
        JdbcTemplate jt = app.getBean(JdbcTemplate.class);
        String sql="insert into account values(?,?)";
        //List<Object[]>
        //List的长度就是sql语句要执行的次数
        //Object[]:每次执行要用的参数
        ArrayList<Object[]> obj = new ArrayList<Object[]>();
        obj.add(new Object[]{"张三",7000});
        obj.add(new Object[]{"李四",8000});
        obj.add(new Object[]{"王五",9000});
        obj.add(new Object[]{"赵六",6000});
        //返回的是一个数组,表示每条sql语句影响的行数
        int[] is = jt.batchUpdate(sql, obj);
        for(int i:is)
            System.out.println("影响的行数:"+i);

在这里插入图片描述
在这里插入图片描述


查询某条记录,封装为一个java对象,并返回

JavaBean对象的属性名需要和数据库中的字段名一致,否则无法完成数据的封装,当前也可以在编写查询sql语句的时候,通过对数据库每列的名称起一个别名,来达到封装的目的

这里的属性名依旧是set方法,去掉set,首字母小写得到的字符串,因此set方法必不可少

jdbcTemplate在方法级别进行了区分: 查询集合,查询单个对象

  • 查询集合: jt.query();
  • 查询单个对象:jt.queryForObject(); 如果查询没结果就会报错,如果查询出来多个结果也会报错

friend类:

public class friend {
    String name;
    Integer money;

    public void setName(String name) {
        this.name = name;
    }

    public void setMoney(Integer money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "friend{" +
                "name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

主类:

        ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
        JdbcTemplate jt = app.getBean(JdbcTemplate.class);
          String sql="SELECT * FROM account WHERE NAME=?";
          //RowMapper: 每一条记录和javabean的属性和数据库里面一行记录进行映射
          friend f=null;
        f = jt.queryForObject(sql, new BeanPropertyRowMapper<friend>(friend.class), "张三");
        System.out.println(f);

在这里插入图片描述


查询集合

        ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
        JdbcTemplate jt = app.getBean(JdbcTemplate.class);
          String sql="SELECT * FROM account ";
          //封装为List:集合里面的元素类型
        List<friend> query = jt.query(sql, new BeanPropertyRowMapper<friend>(friend.class));
          for(friend e:query)
          {
              System.out.println(e);
          }

在这里插入图片描述


查询单条数据

        ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
        JdbcTemplate jt = app.getBean(JdbcTemplate.class);
          String sql="SELECT MAX(money) FROM account";
          //无论是返回单个数据还是单个对象,都是调用queryForObject
        Integer moneyMax = jt.queryForObject(sql, Integer.class);
        System.out.println("最高工资为:"+moneyMax);

在这里插入图片描述


使用带有具名参数的sql语句插入一条员工记录,并以Map的形式传入参数值

具名参数: (具有名字的参数,参数不是一个占位符了,而是以个变量名)

语法格式 --------------------> :参数名

需要使用spring的一个支持具名参数的springTemplate类

占位符参数: ?的顺序不能乱,传参的时候要注意

以map的形式传入参数

代码:

        ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
        JdbcTemplate jt = app.getBean(JdbcTemplate.class);
        NamedParameterJdbcTemplate npjt = app.getBean(NamedParameterJdbcTemplate.class);
        String sql="insert into account(name,money) values(:name,:money)";
        //将有具名参数的值都放在map容器中
        Map<String, Object> Map = new HashMap<String,Object>();
          Map.put("name","大忽悠");
          Map.put("money",8000);
        int row = npjt.update(sql,Map);
        System.out.println("影响的行数:"+row);

在这里插入图片描述


以SqlParameterSource的形式传入参数

使用该方法前,要确保自定义类中有get方法,因为该方法实现原理是从传入的对象中,找对象的get方法,去掉get,首字母小写,看得到的字符串是否和具名参数匹配.

        ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
        JdbcTemplate jt = app.getBean(JdbcTemplate.class);
        NamedParameterJdbcTemplate npjt = app.getBean(NamedParameterJdbcTemplate.class);
        String sql="insert into account(name,money) values(:name,:money)";
           friend f=new friend();
           f.setMoney(20000);
           f.setName("小朋友");
        int row = npjt.update(sql, new BeanPropertySqlParameterSource(f));
        System.out.println("影响的行数"+row);

在这里插入图片描述


使用注解完成对JdbcTemplate的注入----小规模常用

test类:

@Component("test")
public class test {
    @Autowired //按照类型注入
   private JdbcTemplate jdbcTemplate;
    int getJBDCTemplate(friend f)
    {
        int row = jdbcTemplate.update("insert into account values(?,?)", f.getName(), f.getMoney());
        return row;
    }
}

jdbc测试类:

        ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
        test t=(test)app.getBean("test");
        friend f=new friend();
        f.setName("超级大忽悠");
        f.setMoney(40000);
        int row = t.getJBDCTemplate(f);
        System.out.println("影响的行数"+row);

配置文件:

<!--组件扫描-->
    <context:component-scan base-package="com.jdbcTemplate"/>
        <!--数据源对象-->
     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
         <property name="driverClass" value="${jdbc.driver}"/>
         <property name="jdbcUrl" value="${jdbc.url}"/>
         <property name="user" value="${jdbc.username}"/>
         <property name="password" value="${jdbc.password}"/>
     </bean>

   <!--jdbc模板对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
    </bean>

在这里插入图片描述


声明式事务

数据库环境搭建—账户表,图书表,图书库存表

account账号表:
在这里插入图片描述

book图书表:
在这里插入图片描述

book_stock图书库存表:
在这里插入图片描述

jdbc.properties的配置文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/tx
jdbc.username=root
jdbc.password=126433

数据源配置并直接注入到jdbcTemplate中

    <!--加载jdbc.properties-->
    <!--引入context命名空间-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
     <!--组件扫描-->
    <context:component-scan base-package="com.BookCheck"/>
    <!--数据源对象-->
     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
         <property name="driverClass" value="${jdbc.driver}"/>
         <property name="jdbcUrl" value="${jdbc.url}"/>
         <property name="user" value="${jdbc.username}"/>
         <property name="password" value="${jdbc.password}"/>
     </bean>

   <!--jdbc模板对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
    </bean>

Dao层和Service层的类环境搭建

BookDao类:

@Repository
public class BookDao {
    @Autowired
   private JdbcTemplate jdbcTemplate;
    /*减去某个用户的剩余金额*/
    public void updateBalance(String username,int price)
    {
        String sql="update account set money=money-? where name=?";
         jdbcTemplate.update(sql,price,username);
    }
    /*获取某本图书的价格*/
    public int getBookPrice(String isbn)
    {
          String sql="select price from book where ISBN=?";
       return jdbcTemplate.queryForObject(sql, Integer.class,isbn);
    }
    /*减去某本书库存*/
    public void updateStock(String isbn)
    {
        String sql="update book_stock set stock=stock-1 where isbn=?";
        jdbcTemplate.update(sql,isbn);
    }
}

Service类:

@Service
public class BookService {
    @Autowired
    BookDao bookDao;
    /*结账*/
    public void checkOut(String username,String isbn)
    {
        //1.减去库存
        bookDao.updateStock(isbn);
        //2.获取图书的价格
        int bookPrice = bookDao.getBookPrice(isbn);
        //3.减去余额
        bookDao.updateBalance(username,bookPrice);
    }

}

主类:

public class test {
  static  ApplicationContext ioc= new ClassPathXmlApplicationContext("appOfDao.xml");
    public static void main(String[] args) {
        BookService bs = ioc.getBean(BookService.class);
        bs.checkOut("大忽悠","ISBN_001");
        System.out.println("结账成功");
    }

}

在这里插入图片描述


声明式事务

事务管理器(事务切面)

Spring只是个容器,因此它并不做任何事务的具体实现。他只是提供了事务管理的接口PlatformTransactionManager,具体内容由就由各个事务管理器来实现。

在这里插入图片描述

事务管理器可以在目标方法运行前后进行事务控制

目前使用DataSourceTransactionManager

第一步:配置事务管理器,让其进行事务控制

第二步: 开启基于注解的事务控制模式,依赖tx命名空间

<!--创建事务管理器对象-->
    <!--需要导入aspectj的坐标,即面向切面编程的坐标-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!--操作事务需要连接对象,连接对象在连接池中(数据源)-->
    <!--控制数据源,通过操作connection连接,来进行事务的回滚,自动提交操作-->
        <property name="dataSource" ref="dataSource"/>
    </bean>

<!--开启基于注解的事务控制模式,依赖tx命名空间-->
    <tx:annotation-driven transaction-manager="transactionManager"/>

第三步:给事务方法加上注解即可

加上注解之后,如果事务方法里面出现异常,那么整个事务方法会进行回滚,数据恢复原样

在这里插入图片描述


@Transactional注解里面的属性分析

timeout---->参数值为int(秒为单位),超时,事务超出指定执行时长后自动终止并回滚

    @Transactional(timeout = 3)
    public void checkOut(String username,String isbn)
    {
        //1.减去库存
        bookDao.updateStock(isbn);
        //2.获取图书的价格
        int bookPrice = bookDao.getBookPrice(isbn);
        //3.减去余额
        bookDao.updateBalance(username,bookPrice);
    }

readOnly---->参数值为bool,设置事务为只读,可以进行事务优化,默认readOnly=false,改为readOnly=true后,可以加快查询速度,因此不用管事务的相关操作了(设置自动提交…)

如果事务方法中有增删改相关操作,还设置为true时,运行时会报错

    /*结账*/
    @Transactional(readOnly = false)
    public void checkOut(String username,String isbn)
    {
        //1.减去库存
        bookDao.updateStock(isbn);
        //2.获取图书的价格
        int bookPrice = bookDao.getBookPrice(isbn);
        //3.减去余额
        bookDao.updateBalance(username,bookPrice);
    }

异常分类

在这里插入图片描述

noRollbackFor---->参数值为Class[] (字节码文件类型,是个数组) ,那些异常事务可以不回滚

noRollbackForClassName---->参数值为String[] (全类名) ,那些异常事务可以不回滚

可以让原来默认回滚的异常给它不回滚

    @Transactional(noRollbackFor ={ArithmeticException.class,NullPointerException.class} )
    //数学异常不回滚,空指针异常不回滚
    public void checkOut(String username,String isbn)
    {
        //1.减去库存
        bookDao.updateStock(isbn);
        //2.获取图书的价格
        int bookPrice = bookDao.getBookPrice(isbn);
        //3.减去余额
        bookDao.updateBalance(username,bookPrice);

    }


rollbackFor---->参数值为Class[] (字节码文件类型) ,哪些异常事务需要回滚

rollbackForClassName---->参数值为String[] (全类名),哪些异常事务需要回滚

原本不回滚的异常指定让其回滚,原本编译时异常不会回滚

    @Transactional(rollbackFor = {FileNotFoundException.class})
    //文件异常回滚
    public void checkOut(String username,String isbn)
    {
        //1.减去库存
        bookDao.updateStock(isbn);
        //2.获取图书的价格
        int bookPrice = bookDao.getBookPrice(isbn);
        //3.减去余额
        bookDao.updateBalance(username,bookPrice);

    }

ioslation调整隔离级别

前置知识:数据库事务并发问题

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

同时对一个数据进行修改(并发修改同一个数据下的排队,挨个按照顺序进行修改操作)

在这里插入图片描述

前置知识:隔离级别

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


前置知识:查询mysql的隔离级别

在这里插入图片描述

前置知识:事务操作

在这里插入图片描述

前置知识:修改mysql的隔离级别

例如:

set [session|global]  transaction isolation level  read uncommitted

有事务的业务逻辑,容器中保存的是这个业务逻辑的代理对象(了解即可)

在这里插入图片描述


事务传播行为(事务的传播和事务的行为)

如果有多个事务同时进行嵌套运行,子事务是否要和大事务共同用一个事务

在这里插入图片描述
在这里插入图片描述


简单理解: 一个事务相等于一辆车,如果子事务和大事务共同用一个事务,那么可以理解为子事务和大事务位于同一辆车上。如果子事务开启一个新事务,相当于子事务开了一辆新车,大事务和子事务位于不同的车上面

在这里插入图片描述

注意: 出现的异常回一层一层往上面进行传递,坐一辆车的全崩,开新车并且在异常之前执行的不崩;开新车,但是位于异常之后,崩。

注意:如果子事务出现了异常,并且子事务位于大事务的方法体内部,那么大事务会感受到异常,那么即便大事务和子事务开不同的车,大事务也会崩掉,因为方法体内部出现了异常

子事务只和上一级的事务坐一辆车,不会和上一级的上一级的事务坐一辆车,除非他的上一级的事务和他的上一级的上一级的事务坐一辆车

总结图

在这里插入图片描述


设置事务传播行为演示

@Repository
public class BookDao {
    @Autowired
   private JdbcTemplate jdbcTemplate;
    /*减去某个用户的剩余金额*/
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateBalance(String username,int price)
    {
        String sql="update account set money=money-? where name=?";
         jdbcTemplate.update(sql,price,username);
    }
    /*获取某本图书的价格*/
    
    public int getBookPrice(String isbn)
    {
          String sql="select price from book where ISBN=?";
       return jdbcTemplate.queryForObject(sql, Integer.class,isbn);
    }
    /*减去某本书库存*/
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateStock(String isbn)
    {
        String sql="update book_stock set stock=stock-1 where isbn=?";
        jdbcTemplate.update(sql,isbn);
    }
}
    @Transactional(propagation = Propagation.REQUIRED)
    //文件异常回滚
    public void checkOut(String username,String isbn)
    {
        //1.减去库存
        bookDao.updateStock(isbn);
        //2.获取图书的价格
        int bookPrice = bookDao.getBookPrice(isbn);
        //3.减去余额
        bookDao.updateBalance(username,bookPrice);
    }

在这里插入图片描述


重点:REQUIRED事务属性来源于大事务(子事务和大事务坐一辆车时),即子事务的所有属性,例如超时设置,回滚设置,都继承于大事务,即使子事务里面设置了,也没有用

propagation = Propagation.REQUIRES_NEW可以调整,默认是REQUIRED


REQUIRED将之前事务使用的connection传递给这个事务使用

REQUIRED_NEW这个方法直接使用新的connection


本类事务方法之间的调用就只是一个事务

@Transactional
@Service
public class BookService {
    @Autowired
    BookDao bookDao;
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void checkOut(String username,String isbn)
    {
        //1.减去库存
        bookDao.updateStock(isbn);
        //2.获取图书的价格
        int bookPrice = bookDao.getBookPrice(isbn);
        //3.减去余额
        bookDao.updateBalance(username,bookPrice);
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateStock(String isbn)
    {
       bookDao.updateStock(isbn);
    }

    @Transactional
    void testmain()
    {
        checkOut("大忽悠","ISBN_001");
        updateStock("ISBN_002");
        System.out.println("结账成功");
        int i=10/0;
    }
}

主类:

    public static void main(String[] args) {
        ApplicationContext ioc= new ClassPathXmlApplicationContext("appOfDao.xml");
        BookService bs = ioc.getBean(BookService.class);
        //虽然testmain里面的两个方法都开了新车,
        //但是testmain方法最后出现了异常,效果并不如预期般改变(即回滚了事务)
        bs.testmain();
    }

原因:代理对象调用方法的时候,才能实现事务的控制
在这里插入图片描述

在这里插入图片描述
无法进行事务控制,也就相当于无法通过动态代理,对方法进行增强的操作,无法进行增强的操作,当然也就无法进行事务控制了


在本类中给本类对象进行注入,会造成死循环

在这里插入图片描述
死循环原因: IOC容器创建时,先去实例化BookService对象,实例化BookService时,发现需要给其成员变量bookService装配对象,为了给成员变量装配对象,会去容器中找对应类型的对象,结果找到了还没创建的对象BookService对象(还没创建是因为正在为其成员变量赋值),于是又去给他创建对象…


事务控制的xml配置:依赖tx名称空间和aop名称空间

要导入spring-tx坐标,spring处理事务相关的坐标

切点方法事务配置参数

在这里插入图片描述

1.引入依赖

    <!--导入aspectj的坐标-->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.4</version>
    </dependency>
    <!--导入spring的坐标-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.0.5.RELEASE</version>
    </dependency>
    <!--引入Spring测试坐标-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.0.5.RELEASE</version>
    </dependency>
    <!--junit坐标-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.1</version>
    </dependency>
    <!--mysql驱动的坐标-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.32</version>
    </dependency>
    <!--c3p0数据库连接池的坐标-->
    <dependency>
      <groupId>c3p0</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.1.2</version>
    </dependency>
    <!--druid数据库连接池坐标-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.10</version>
    </dependency>
    <!--spring jdbc的坐标-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.0.5.RELEASE</version>
    </dependency>
    <!--spring tx的坐标,处理事务的-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.0.5.RELEASE</version>
    </dependency>

2.开启注解扫描—引入context命名空间

<!--组件扫描-->
    <context:component-scan base-package="com.BookCheck"/>

3.引入properties配置文件

    <!--加载jdbc.properties-->
    <!--引入context命名空间-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

4.创建数据源dataSource

    <!--数据源对象-->
     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
         <property name="driverClass" value="${jdbc.driver}"/>
         <property name="jdbcUrl" value="${jdbc.url}"/>
         <property name="user" value="${jdbc.username}"/>
         <property name="password" value="${jdbc.password}"/>
     </bean>

5.创建JdbcTemplate对象

 <!--jdbc模板对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
    </bean>

6.创建事务管理器对象: 增强(通知)

 <!--配置平台事务管理器-->
    <!--需要导入aspectj的坐标,即面向切面编程的坐标-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!--获取数据库连接池对象-->
        <property name="dataSource" ref="dataSource"/>
    </bean>

7.事务增强:对方法的过滤

    <!--通知:事务增强
    transaction-manager="transactionManager":指定配置的是哪一个事务管理器
     -->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
    <!--事务属性-->
<tx:attributes>
    <!--指名哪个方法是事务方法: 切入点表达式只是说,事务管理器要切入这些方法,
    哪些方法要加事务使用tx:method指定-->
    <tx:method name="*"/><!--所有方法都加上事务管理-->
    <!-- -1代表用于不会超时-->
    <tx:method name="checkOut" propagation="REQUIRED" timeout="-1"></tx:method>
    <tx:method name="check*"></tx:method>
    <!--所有以get开头的方法,都设置为只读,加快速度-->
    <tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>

8.配置aop

<!--配置事务的aop织入-->
    <aop:config>
        <!--切点表达式的抽取-->
        <aop:pointcut id="txPoint" expression="execution(* com.BookCheck.Service.BookService.*(..))"/>
        <!--事务建议:事务增强-->
        <aop:advisor advice-ref="myAdvice" pointcut-ref="txPoint"/>
    </aop:config>

赞(0) 打赏
未经允许不得转载:IDEA激活码 » Spring入门后半部分----JDBCTemplate和事务控制

相关推荐

  • 暂无文章

一个分享Java & Python知识的社区