66-Spring的JDBCTemplate与声明式事务

Spring的JDBCTemplate与声明式事务

Spring的JdbcTemplate:
除了前面说过的连接池来操作数据库连接,Spring也提供了类似的操作,如下
JdbcTemplate是什么?
JdbcTemplate是spring框架中提供的一个模板对象,是对原始繁琐的Jdbc API对象的简单封装
核心对象:
JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSource dataSource);
核心方法:
/*
int update(); 执行增、删、改语句
List  query(); 查询多个
T queryForObject(); 查询一个
 new BeanPropertyRowMapper<>(); 实现ORM映射封装

*/
举个栗子:
查询数据库所有账户信息到Account实体中:
public class JdbcTemplateTest {
    @Test
    public void testFindAll() throws Exception {
        // 创建核心对象
        JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
        // 编写sql
        String sql = "select * from account";
        // 执行sql
        List<Account> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Account.class));
   }
}

Spring整合JdbcTemplate :
需求
基于Spring的xml配置实现账户的CRUD案例
步骤分析:
/*
1. 创建java项目,导入坐标
2. 编写Account实体类
3. 编写AccountDao接口和实现类
4. 编写AccountService接口和实现类
5. 编写spring核心配置文件
6. 编写测试代码
*
创建java项目,导入坐标 :
<dependencies>
    <dependency>
        
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
        <version>5.1.47version>
    dependency>
    <dependency>
        
        <groupId>com.alibabagroupId>
        <artifactId>druidartifactId>
        <version>1.1.15version>
    dependency>
    <dependency>
        
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-contextartifactId>
        <version>5.1.5.RELEASEversion>
    dependency>
    <dependency>
        
        <groupId>org.aspectjgroupId>
        <artifactId>aspectjweaverartifactId>
        <version>1.8.13version>
    dependency>
    <dependency>
          
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-jdbcartifactId>
        <version>5.1.5.RELEASEversion>
    dependency>
    <dependency>
        
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-txartifactId>
        <version>5.1.5.RELEASEversion>
    dependency>
    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>4.12version>
    dependency>
    <dependency>
        
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-testartifactId>
        <version>5.1.5.RELEASEversion>
    dependency>
dependencies>
编写Account实体类:
package com.domain;

/**
 *
 */
public class Account {
    private Integer id;
    private String name;
    private Double money;

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

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Double getMoney() {
        return money;
    }

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

编写AccountDao接口和实现类:
package com.dao;

import com.domain.Account;

import java.util.List;

/**
 *
 */
public interface AccountDao {

    public List<Account> findAll();

    public Account findById(Integer id);

    public void save(Account account);

    public void update(Account account);

    public void delete(Integer id);

}

package com.dao.impl;

import com.dao.AccountDao;
import com.domain.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.List;


/**
 *
 */
@Repository
public class AccountDaoImpl implements AccountDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;


    @Override
    public List<Account> findAll() {
        //需要用到JDBCTemplate

        String sql = "select * from account";
        List<Account> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Account>
                                                 (Account.class));
        return query;
    }

    @Override
    public Account findById(Integer id) {
        String sql = "select * from account where id = ?";
        Account account = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Account>
                                                      (Account.class), id);
        return account;
    }

    @Override
    public void save(Account account) {
        String sql = "insert into values(null,?,?)";
        jdbcTemplate.update(sql, account.getName(), account.getMoney());
        //查询需要对应对象,增删改不需要

    }

    @Override
    public void update(Account account) {
        String sql = "update account set name = ?,money = ? where id = ?";
        jdbcTemplate.update(sql, account.getName(), account.getMoney(), account.getId());


    }

    @Override
    public void delete(Integer id) {
        String sql = "delete from account where id = ?";
        jdbcTemplate.update(sql, id);

    }
}

编写AccountService接口和实现类:
package com.service;

import com.domain.Account;

import java.util.List;

/**
 *
 */
public interface AccountService {

    public List<Account> findAll();

    public Account findById(Integer id);

    public void save(Account account);

    public void update(Account account);

    public void delete(Integer id);

}

package com.service.impl;

import com.dao.AccountDao;
import com.service.AccountService;
import com.domain.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 *
 */

@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao aDao;


    public void setAccountDao(AccountDao accountDao) {
        this.aDao = accountDao;
    }

    @Override
    public List<Account> findAll() {

        return aDao.findAll();
    }

    @Override
    public Account findById(Integer id) {
        return aDao.findById(id);
    }

    @Override
    public void save(Account account) {
        aDao.save(account);
    }

    @Override
    public void update(Account account) {
        aDao.update(account);

    }

    @Override
    public void delete(Integer id) {
        aDao.delete(id);
    }
}

编写spring核心配置文件 :
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring_db?characterEncoding=utf8
jdbc.username=root
jdbc.password=123456

<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"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

<context:component-scan base-package="com.lagou">context:component-scan>

    <context:property-placeholder location="classpath:jdbc.properties"/>


    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}">property>
        <property name="url" value="${jdbc.url}">property>
        <property name="username" value="${jdbc.username}">property>
        <property name="password" value="${jdbc.password}">property>

    bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource">constructor-arg>
    bean>
beans>
编写测试代码:
package com.lagou.test;

import com.lagou.domain.Account;
import com.lagou.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

/**
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AccountServiceTest {

    @Autowired
    private AccountService accountService;



    @Test
    public void testSave(){
        Account account = new Account();
        account.setName("张三");
        account.setMoney(1000.0);
        accountService.save(account);

    }

    //查询所有
    @Test
    public void testFindAll(){
        List<Account> all = accountService.findAll();
        for (Account account : all) {
            System.out.println(account);
        }
    }

    //根据ID查询
    @Test
    public void testFindOne(){
        Account account = accountService.findById(1);
        System.out.println(account);
    }

    //更新
    @Test
    public void testUpdate(){
        Account account = new Account();
        account.setId(1);
        account.setName("李四");
        account.setMoney(2000.0);
        accountService.update(account);
    }

    //删除
    @Test
    public void testDelete(){
        accountService.delete(4);
    }

}

实现转账案例:
步骤分析:
/*
1. 创建java项目,导入坐标
2. 编写Account实体类
3. 编写AccountDao接口和实现类
4. 编写AccountService接口和实现类
5. 编写spring核心配置文件
6. 编写测试代码
*/
创建java项目,导入坐标 :
<dependencies>
    <dependency>
        
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
        <version>5.1.47version>
    dependency>
    <dependency>
        
        <groupId>com.alibabagroupId>
        <artifactId>druidartifactId>
        <version>1.1.15version>
    dependency>
    <dependency>
        
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-contextartifactId>
        <version>5.1.5.RELEASEversion>
    dependency>
    <dependency>
        
        <groupId>org.aspectjgroupId>
        <artifactId>aspectjweaverartifactId>
        <version>1.8.13version>
    dependency>
    <dependency>
        
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-jdbcartifactId>
        <version>5.1.5.RELEASEversion>
    dependency>
    <dependency>
         
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-txartifactId>
        <version>5.1.5.RELEASEversion>
    dependency>
    <dependency>
        
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>4.12version>
    dependency>
    <dependency>
        
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-testartifactId>
        <version>5.1.5.RELEASEversion>
    dependency>
dependencies>
编写Account实体类:
package com.lagou.domain;

/**
 *
 */
public class Account {
    private Integer id;
    private String name;
    private Double money;

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

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Double getMoney() {
        return money;
    }

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

编写AccountDao接口和实现类:
package com.lagou.dao;

/**
 *
 */
public interface AccountDao {

    //转出操作 减钱
    public void outMoney(String outUser, double money);

    //转出操作 加钱
    public void inMoney(String inUser, double money);
}

package com.lagou.dao.impl;

import com.lagou.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;


/**
 *
 */
@Repository
public class AccountDaoImpl implements AccountDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;


    @Override
    public void outMoney(String outUser, double money) {
        String sql = "update account set money = money - ? where name = ?";
        jdbcTemplate.update(sql, money, outUser);
    }

    @Override
    public void inMoney(String inUser, double money) {
        String sql = "update account set money = money + ? where name = ?";
        jdbcTemplate.update(sql, money, inUser);
    }
}




编写AccountService接口和实现类:
package com.lagou.service;

/**
 *
 */
public interface AccountService {

    //转账方法
    public void transfer(String outUser, String inUser, Double money);

}

package com.lagou.service.impl;

import com.lagou.dao.AccountDao;
import com.lagou.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 *
 */

@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;


    @Override
    public void transfer(String outUser, String inUser, Double money) {

        accountDao.outMoney(outUser, money);
        accountDao.inMoney(inUser, money);
    }

    
}

编写spring核心配置文件:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring_db?characterEncoding=utf8&useSSL=false
# 加上useSSL=false防止使用注解时,出现的关闭错误,默认是true
jdbc.username=root
jdbc.password=123456

<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"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

<context:component-scan base-package="com.lagou">context:component-scan>

    <context:property-placeholder location="classpath:jdbc.properties"/>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}">property>
        <property name="url" value="${jdbc.url}">property>
        <property name="username" value="${jdbc.username}">property>
        <property name="password" value="${jdbc.password}">property>

    bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource">constructor-arg>
    bean>
beans>
编写测试代码:
package com.lagou.test;

import com.lagou.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
//这两个注解是一起的,当然了main方法也是可以执行的
public class AccountServiceTest {

    @Autowired
    //由于扫描时,直接忽略静态的,即注解不操作静态的
    //所以当你是静态时,无论什么情况,都不会使得你报错,比如没有对应对象等等(因为不会找)
    private AccountService accountService;


    @Test
   public void textTransfer(){
       accountService.transfer("李四","jerry",100d);
   }
}

Spring的事务 :
Spring中的事务控制方式:
Spring的事务控制可以分为编程式事务控制和声明式事务控制
编程式:
开发者直接把事务的代码和业务代码耦合到一起,在实际开发中不用
声明式:
开发者采用配置的方式来实现的事务控制,业务代码与事务代码实现解耦合,使用的AOP思想
编程式事务控制相关对象:
PlatformTransactionManager:
PlatformTransactionManager接口,是spring的事务管理器,里面提供了我们常用的操作事务的方法

66-Spring的JDBCTemplate与声明式事务_第1张图片

注意:
/*
PlatformTransactionManager 是接口类型,不同的 Dao 层技术则有不同的实现类
Dao层技术是jdbcTemplate或mybatis时:
 DataSourceTransactionManager 也是需要对应数据源的,是为了可以创建新的事务
 
Dao层技术是hibernate时:
 HibernateTransactionManager
 
Dao层技术是JPA时:
 JpaTransactionManager
*/
TransactionDefinition :
TransactionDefinition接口提供事务的定义信息(事务隔离级别、事务传播行为等等)

66-Spring的JDBCTemplate与声明式事务_第2张图片

事务隔离级别:
设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读(幻读)
/*
ISOLATION_DEFAULT 使用数据库默认级别
 
ISOLATION_READ_UNCOMMITTED 读未提交
 
ISOLATION_READ_COMMITTED 读已提交
 
ISOLATION_REPEATABLE_READ 可重复读
 
ISOLATION_SERIALIZABLE 串行化

*/
事务传播行为:
事务传播行为指的就是当一个业务方法【被】另一个业务方法调用时,应该如何进行事务控制

66-Spring的JDBCTemplate与声明式事务_第3张图片

事务挂起,相当于将对应连接保存起来,后面再自己进行相应操作,如创建连接等等再次进行事务操作
注意:是有上面设置的方法的传播(有对应事务管理,这是需要对应判断),即其他方法没有对应设置,就当作一个普通方法而已
而加入,就相当于判断,然后是否进行连接的创建或者开启事务等等

66-Spring的JDBCTemplate与声明式事务_第4张图片

/*
read-only(是否只读):建议查询时设置为只读
timeout(超时时间):默认值是-1,没有超时限制。如果有,以秒为单位进行设置
*/
TransactionStatus:
TransactionStatus 接口提供的是事务具体的运行状态

66-Spring的JDBCTemplate与声明式事务_第5张图片

可以简单的理解三者的关系:事务管理器通过读取事务定义参数进行事务管理,然后会产生一系列的事务状态
实现代码:
配置文件:

 <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <property name="dataSource" ref="dataSource"/>
    bean>
业务层代码:
package com.lagou.service.impl;

import com.lagou.dao.AccountDao;
import com.lagou.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;
    @Autowired
    private PlatformTransactionManager transactionManager;

    @Override
    public void transfer(String outUser, String inUser, Double money) {
        // 创建事务定义对象
        //DefaultTransactionDefinition是TransactionDefinition 的实现类
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        // 设置是否只读,false支持事务
        def.setReadOnly(false);
        // 设置事务隔离级别,可重复读mysql默认级别
        def.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
        // 设置事务传播行为,必须有事务
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        // 配置事务管理器
        TransactionStatus status = transactionManager.getTransaction(def);

        try {
            // 转账
            accountDao.outMoney(outUser, money);
            accountDao.inMoney(inUser, money);
            // 提交事务
            transactionManager.commit(status);
        } catch (Exception e) {
            e.printStackTrace();
            // 回滚事务
            transactionManager.rollback(status);
        }
    }
}
知识小结:
Spring中的事务控制主要就是通过这三个API实现的
/*
PlatformTransactionManager 负责事务的管理,它是个接口,其子类负责具体工作
TransactionDefinition 定义了事务的一些相关参数
TransactionStatus 代表事务运行的一个实时状态

*/
理解三者的关系:事务管理器通过读取事务定义参数进行事务管理,然后会产生一系列的事务状态
基于XML的声明式事务控制:
在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。底层采用AOP思想来实现的
声明式事务控制明确事项:
核心业务代码(目标对象,切入点是谁?
事务增强代码(Spring已提供事务管理器,通知是谁?)
切面配置(切面如何配置?)
快速入门 :
需求
使用spring声明式事务控制转账业务
步骤分析:
/*
引入tx命名空间
事务管理器通知配置
事务管理器AOP配置
测试事务控制转账业务代码
*/
引入tx命名空间,事务管理器通知配置,事务管理器AOP配置:

<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
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:component-scan base-package="com.lagou">context:component-scan>

    <context:property-placeholder location="classpath:jdbc.properties"/>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}">property>
        <property name="url" value="${jdbc.url}">property>
        <property name="username" value="${jdbc.username}">property>
        <property name="password" value="${jdbc.password}">property>

    bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource">constructor-arg>
    bean>

    
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    bean>

    
    
    <tx:advice id="advice" transaction-manager="transactionManager">
        
        <tx:attributes>
            <tx:method name="*"/>
        tx:attributes>
    tx:advice>

    
    <aop:config>
        
        
        <aop:advisor advice-ref="advice" pointcut="execution(* 
                                                   com.lagou.service.impl.AccountServiceImpl.*
                                                   (..))"/>
    
    
    aop:config>
beans>
测试事务控制转账业务代码:
 @Test
   public void textTransfer(){
       accountService.transfer("李四","jerry",100d);
   }
事务参数的配置详解(对应的片段) :

  <tx:advice id="advice" transaction-manager="transactionManager">
        
        <tx:attributes>
            
            <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" 
                       timeout="-1"
                       read-only="false"/>
            
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="*"/>
            

        tx:attributes>
    tx:advice>

知识小结:
/*
平台事务管理器配置
事务通知的配置
事务aop织入的配置
*/

基于注解的声明式事务控制:
常用注解:
步骤分析:
/*
修改service层,增加事务注解
修改spring核心配置文件,开启事务注解支持

*/
修改service层,增加事务注解:
 @Override
    //相当于直接指定对应方法,且使用对应配置
    //即会自动使用对应的org.springframework.jdbc.datasource.DataSourceTransactionManager实例的通知方法
    //然后直接指定对应事务配置再对应方法(就是被监听到的方法)上的作用,且进行监听
    //而不用先对对应方法指定配置,最后再进行监听
    //readOnly默认false
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ,timeout = 
                   -1,readOnly = false)
                   //当然也可以直接使用@Transactional(),参数都是默认的也可,括号也可以去掉,即就是@Transactional也可以
    public void transfer(String outUser, String inUser, Double money) {

            accountDao.outMoney(outUser, money);
            //int i = 1/0;
            accountDao.inMoney(inUser, money);

    }
若加在类上,如
@Service
//@Transactional //对下面所有的方法进行操作,即相当于在所有方法上加上@Transactional
public class AccountServiceImpl implements AccountService {
}
//但方法上的会覆盖类的,即局部优先
添加对应的spring核心配置文件,开启事务注解支持:
 
    <tx:annotation-driven>tx:annotation-driven>

注意:在依赖里,若要使用配置文件,不要加上packaging标签,如:
    <groupId>com.lagougroupId>
    <artifactId>jdbc_springartifactId>
    <packaging>pompackaging> 

    <version>1.0-SNAPSHOTversion>
最后要注意:IOC和AOP都是一种方式,也就是说,可以单独使用的,而不是只有他们一起
而在Spring里AOP基本需要IOC的使用,主要是因为AOP基本只会操作IOC的实例,或者说操作IOC比较方便
纯注解:
核心配置类:
package com.lagou.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

/**
 *
 */
@Configuration
//将该类当成配置类,最后将对应该类的实例放入IOC容器中,放在IOC容器的过程中,会先操作变量,最后操作方法
@ComponentScan("com.lagou") //IOC注解扫描
@Import(DataSourceConfig.class)
//导入其他配置类,不是配置类也可以(对应版本必须要配置类,但现在基本可以不是配置类了)
@EnableTransactionManagement //开启事务管理(事务的注解驱动),即扫描事务的注解
public class SpringConfig {

//@Bean生成的名称是方法名(基本一致,没有什么忽略大小写),也可以使用@Bean("dataSource")指定生成的名称是dataSource
    @Bean //由于最后都会变成对象,依次放入,所以DataSource值可以获得
    //实际上可以认为,有参数列表的,比没有参数列表的后进行操作
    public JdbcTemplate getJdbcTemplate(@Autowired DataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        return jdbcTemplate;

    }
    @Bean  //对应的通知方法在这里面
    public PlatformTransactionManager getTransactionManager(@Autowired DataSource dataSource) {
        DataSourceTransactionManager dataSourceTransactionManager = new 
            DataSourceTransactionManager(dataSource);
        return dataSourceTransactionManager;

    }
}


package com.lagou.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;

import javax.sql.DataSource;

/**
 *
 */
@PropertySource("classpath:jdbc.properties") //引入文件,即基本是全局配置
public class DataSourceConfig {
    @Value("${jdbc.driverClassName}")
    private String driverClassName;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    @Bean  //把当前方法的返回值放到IOC容器中,变量先操作,获得对象,然后依次放入IOC容器中
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
}



测试类:
package com.lagou.test;

import com.lagou.config.SpringConfig;
import com.lagou.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)  //这里改变了
//这两个注解是一起的,当然了main方法也是可以执行的
public class AccountServiceTest {

    @Autowired
    //由于扫描时,直接忽略静态的,即注解不操作静态的
    //所以当你是静态时,无论什么情况,都不会使得你报错,比如没有对应对象等等(因为不会找)
    private AccountService accountService;


    @Test
   public void textTransfer(){
       accountService.transfer("李四","jerry",100d);
   }
}

知识小结:
/*
平台事务管理器配置(xml、注解方式)
事务通知的配置(@Transactional注解配置)
事务注解驱动的配置 、@EnableTransactionManagement
*/
Spring集成web环境:
ApplicationContext应用上下文获取方式
应用上下文对象是通过 new ClasspathXmlApplicationContext(spring配置文件) 方式获取的
但是每次从容器中获得Bean时都要编写 new ClasspathXmlApplicationContext(spring配置文件)
这样的弊端是配置文件加载多次,应用上下文对象创建多次
解决思路分析:
在Web项目中,可以使用ServletContextListener监听Web应用的启动,我们可以在Web应用启动时
就加载Spring的配置文件,创建应用上下文对象ApplicationContext
在将其存储到最大的域servletContext域中,这样就可以在任意位置从域中获得应用上下文ApplicationContext对象了
Spring提供获取应用上下文的工具:
上面的分析不用手动实现,Spring提供了一个监听器ContextLoaderListener就是对上述功能的封装
该监听器内部加载Spring配置文件,创建应用上下文对象,并存储到ServletContext域中
提供了一个客户端工具WebApplicationContextUtils供使用者获得应用上下文对象
所以我们需要做的只有两件事:
在web.xml中配置ContextLoaderListener监听器(导入spring-web坐标)
使用WebApplicationContextUtils获得应用上下文对象ApplicationContext
实现:
创建工程时,可以点击如下来创建web工程:

66-Spring的JDBCTemplate与声明式事务_第6张图片

前提将这个勾选才可点击:

在这里插入图片描述

对应依赖,就是对应jar包,封装好了对应操作,网上依赖千千万万,一般外面需要某个jar包时
需要对应jar,而pom.xml帮我们操作了,由于非常多,只要知道大概的jar就可以了
导入Spring集成web的坐标
   <dependencies>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>5.1.5.RELEASEversion>
        dependency>
        <dependency>
            
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webartifactId>
            <version>5.1.5.RELEASEversion>
        dependency>
        <dependency>
            
            <groupId>javax.servletgroupId>
            <artifactId>javax.servlet-apiartifactId>
            <version>3.1.0version>
            <scope>providedscope>
        dependency>
    dependencies>
配置ContextLoaderListener监听器:

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class> 
    listener>  
    

    <context-param>
        
        <param-name>contextConfigLocationparam-name>
        <param-value>classpath:applicationContext.xmlparam-value>
    context-param>
web-app>
通过工具获得应用上下文对象:
package com.lagou.servlet;

import com.lagou.domain.Account;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 *
 */
@WebServlet("/account")
public class AccountServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, 
    IOException {
//        ClassPathXmlApplicationContext classPathXmlApplicationContext = new 
        ClassPathXmlApplicationContext("applicationContext.xml");
//        Account account = (Account) classPathXmlApplicationContext.getBean("account");
//        System.out.println(account);
        //使用监听器ContextLoaderListener
        //使得ClassPathXmlApplicationContext创建的对象,放在ServletContext域中
        WebApplicationContext webApplicationContext = 
            WebApplicationContextUtils.getWebApplicationContext(req.getServletContext());
        //将ServletContext当成参数,使得他帮我们进行封装,然后可以去调用
        Account account = (Account) webApplicationContext.getBean("account");
        System.out.println(account);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, 
    IOException {
        super.doGet(req, resp);
    }
}

实体类:
package com.lagou.domain;

/**
 *
 */
public class Account {
    private Integer id;
    private String name;
    private Double money;

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

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Double getMoney() {
        return money;
    }

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

ount");
//        System.out.println(account);
        //使用监听器ContextLoaderListener
        //使得ClassPathXmlApplicationContext创建的对象,放在ServletContext域中
        WebApplicationContext webApplicationContext = 
            WebApplicationContextUtils.getWebApplicationContext(req.getServletContext());
        //将ServletContext当成参数,使得他帮我们进行封装,然后可以去调用
        Account account = (Account) webApplicationContext.getBean("account");
        System.out.println(account);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, 
    IOException {
        super.doGet(req, resp);
    }
}

实体类:
package com.lagou.domain;

/**
 *
 */
public class Account {
    private Integer id;
    private String name;
    private Double money;

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

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Double getMoney() {
        return money;
    }

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

你可能感兴趣的:(笔记,java,spring)