2.4.7 Spring JDBCTemplate,编程式事务, 声明式事务(基于XML,注解), Spring集成web环境(监听器)

目录

Spring JDBCTemplate & 声明式事务

一 Spring的JdbcTemplate

1.1 JdbcTemplate是什么?

1.2 Spring整合JdbcTemplate

1.4 实现转账案例

二 Spring的事务

2.1 Spring中的事务控制方式

2.2 编程式事务控制相关对象【了解】

2.2.1 PlatformTransactionManager

2.2.2 TransactionDefinition

2.2.3 TransactionStatus

2.2.4 实现代码

2.2.5 知识小结

2.3 基于XML的声明式事务控制【重点】

2.3.1 快速入门

2.3.2 事务参数的配置详解

2.3.3 知识小结

2.4 基于注解的声明式事务控制【重点】

2.4.1 常用注解

2.4.2 纯注解

2.4.3 知识小结

三 Spring集成web环境

3.1 ApplicationContext应用上下文获取方式

3.2 Spring提供获取应用上下文的工具

3.3 实现


 

Spring JDBCTemplate & 声明式事务

课程任务主要内容:

* Spring的JdbcTemplate
* Spring的事务
* Spring集成web环境


一 Spring的JdbcTemplate

1.1 JdbcTemplate是什么?

JdbcTemplate是spring框架中提供的一个模板对象,是对原始繁琐的Jdbc API对象的简单封装。
核心对象

JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSource dataSource);

核心方法

int update(); 执行增、删、改语句
List<T>  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));
    }
}

 

1.2 Spring整合JdbcTemplate

需求
     基于Spring的xml配置实现账户的CRUD案例
步骤分析

1. 创建java项目,导入坐标
2. 编写Account实体类
3. 编写AccountDao接口和实现类
4. 编写AccountService接口和实现类
5. 编写spring核心配置文件
6. 编写测试代码

1)创建java项目,导入坐标

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.lagou</groupId>
    <artifactId>spring_jdbctemplate</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--指定编码及JDK版本-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <java.version>1.11</java.version>
        <maven.compiler.source>1.11</maven.compiler.source>
        <maven.compiler.target>1.11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.15</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>

        <!-- 以下两个为jdbcTemplate和事务的jar包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

    </dependencies>
</project>

2)编写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 +
                '}';
    }

    ...
}

3)编写AccountDao接口和实现类

package com.lagou.dao;

public interface AccountDao {

    /*
        查询所有账户
     */
    public List<Account> findAll();

    /*
        根据ID查询账户
     */
    public Account findById(Integer id);

    /*
        添加账户
     */
    public void save(Account account);

    /*
        更新账户信息
     */
    public void update(Account account);

    /*
        根据ID删除账户
     */
    public void delete(Integer id);


}
package com.lagou.dao.impl;

// 生成该类实例存到IOC容器中, 以供service调用
@Repository
public class AccountDaoImpl implements AccountDao {

    // 这里就要先注入这个实例
    @Autowired
    private JdbcTemplate jdbcTemplate;

    /*
        查询所有账户
     */
    public List<Account> findAll() {

        // 需要用到jdbcTemplate, 因为用的是spring  所以可以从容器中拿
        String sql = "select * from account";
        List<Account> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Account>(Account.class));

        return list;
    }

    /*
        根据ID查询账户
     */
    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;
    }

    /*
        添加账户
     */
    public void save(Account account) {
        String sql = "insert into account values(null,?,?)";
        jdbcTemplate.update(sql,account.getName(),account.getMoney());


    }

    /*
        更新账户
     */
    public void update(Account account) {
        String sql = "update account set money = ? where name = ?";
        jdbcTemplate.update(sql,account.getMoney(),account.getName());

    }

    /*
        根据ID删除账户
     */
    public void delete(Integer id) {
        String sql = "delete from account where id = ?";
        jdbcTemplate.update(sql,id);

    }
}

4)编写AccountService接口和实现类

package com.lagou.servlet;

public interface AccountService {

    /*
       查询所有账户
    */
    public List<Account> findAll();

    /*
        根据ID查询账户
     */
    public Account findById(Integer id);

    /*
        添加账户
     */
    public void save(Account account);

    /*
        更新账户信息
     */
    public void update(Account account);

    /*
        根据ID删除账户
     */
    public void delete(Integer id);
}
package com.lagou.servlet.impl;

// 交给spring生成实例
@Service
public class AccountSerivceImpl implements AccountService {

    // 注入dao实例
    @Autowired
    private AccountDao accountDao;
    
    public List<Account> findAll() {
        
        List<Account> all = accountDao.findAll();
        return all;
    }

    public Account findById(Integer id) {
        
        Account account = accountDao.findById(id);
        return account;
    }

    public void save(Account account) {

        accountDao.save(account);
    }

    public void update(Account account) {

        accountDao.update(account);
    }

    public void delete(Integer id) {

        accountDao.delete(id);
    }
}

5)编写spring核心配置文件

 

<?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"
       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">

    <!--IOC注解扫描-->
    <context:component-scan base-package="com.lagou"/>

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

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

    <!--jdbcTemplate, 是非自定义jar包, 无法在类中配置注解, 因此要在这里配置bean标签
        由源码看出, 需要传入一个数据源对象, spring才能自动生成本对象, 所以要先配置生成数据源的bean标签 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource"/>
    </bean>
</beans>

6)编写测试代码

package com.lagou.test;

// spring测试专用注解, 以及读取配置文件(要加classpath:)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:applicationContext.xml"})
public class AccountServiceImplTest {

    @Autowired
    private AccountService accountService;

    // 测试保存
    @Test
    public void testSave(){

        Account account = new Account();
        account.setName("lucy");
        account.setMoney(1000d);
        accountService.save(account);
    }

    // 测试查询所有
    @Test
    public void testFindAll(){

        List<Account> all = accountService.findAll();
        for (Account account : all) {
            System.out.println(account);
        }
    }

    //测试根据ID进行查询
    @Test
    public void testFindById(){

        Account account = accountService.findById(1);
        System.out.println(account);
    }


    // 测试账户修改
    @Test
    public void testUpdate(){

        Account account = new Account();
        account.setName("tom");
        account.setMoney(1000d);

        accountService.update(account);
    }

    // 测试根据ID删除账户
    @Test
    public void testDelete(){

        accountService.delete(4);
    }
}

 

1.4 实现转账案例

步骤分析

1. 创建java项目,导入坐标
2. 编写Account实体类
3. 编写AccountDao接口和实现类
4. 编写AccountService接口和实现类
5. 编写spring核心配置文件
6. 编写测试代码


1)创建java项目,导入坐标

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.lagou</groupId>
    <artifactId>spring_transfer_tx</artifactId>
    <version>1.0-SNAPSHOT</version>


    <!--指定编码及JDK版本-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <java.version>1.11</java.version>
        <maven.compiler.source>1.11</maven.compiler.source>
        <maven.compiler.target>1.11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.15</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>

        <!-- 以下两个为jdbcTemplate和事务的jar包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

    </dependencies>
</project>

2)编写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 +
                '}';
    }
}

3)编写AccountDao接口和实现类

package com.lagou.dao;

public interface AccountDao {

    /*
        减钱:转出操作
     */
    public void out(String outUser, Double money);

    /*
       加钱:转入操作
    */
    public void in(String inUser, Double money);
}
package com.lagou.dao.impl;

// spring生成该类的实例存入IOC, 则在service中可以直接注入使用
@Repository
public class AccountDaoImpl implements AccountDao {

    // 注入jdbcTemplate对象
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void out(String outUser, Double money) {
        String sql = "update account set money = money - ? where name = ?";
        jdbcTemplate.update(sql,money,outUser);
    }

    public void in(String inUser, Double money) {
        String sql = "update account set money = money + ? where name = ?";
        jdbcTemplate.update(sql,money,inUser);
    }
}

4)编写AccountService接口和实现类

package com.lagou.servlet;

public interface AccountSerivce {

    /*
        转账方法
     */

    public void transfer(String outUser, String inUser, Double money);
}
package com.lagou.servlet.impl;

@Service
public class AccountServiceImpl implements AccountSerivce {

    @Autowired
    private AccountDao accountDao;

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

        //调用dao的out及in方法
        accountDao.out(outUser,money);

        accountDao.in(inUser,money);
    }
}

5)编写spring核心配置文件

<?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
		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
">

   <!-- IOC注解扫描-->
    <context:component-scan base-package="com.lagou"></context:component-scan>


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

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

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

</beans>

6)编写测试代码

package com.lagou.test;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:applicationContext.xml"})
public class AccountServiceImplTest {

    @Autowired
    private AccountSerivce accountSerivce;

    @Test
    public void testTransfer(){
        accountSerivce.transfer("tom","jerry",100d);
    }
}

 

二 Spring的事务

2.1 Spring中的事务控制方式

Spring的事务控制可以分为编程式事务控制和声明式事务控制。

编程式
开发者直接把事务的代码和业务代码耦合到一起,在实际开发中不用。

声明式
开发者采用配置的方式来实现的事务控制,业务代码与事务代码实现解耦合,使用的AOP思想。

 

2.2 编程式事务控制相关对象【了解】

2.2.1 PlatformTransactionManager

PlatformTransactionManager接口,是spring的事务管理器,里面提供了我们常用的操作事务的方法。

注意:

* PlatformTransactionManager 是接口类型,不同的 Dao 层技术则有不同的实现类。

* Dao层技术是jdbcTemplate或mybatis时:
        DataSourceTransactionManager

* Dao层技术是hibernate时:
        HibernateTransactionManager

* Dao层技术是JPA时:
        JpaTransactionManager

 

2.2.2 TransactionDefinition

TransactionDefinition接口提供事务的定义信息(事务隔离级别、事务传播行为等等)

1)事务隔离级别

设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读(幻读)。

* ISOLATION_DEFAULT                           使用数据库的默认级别

* ISOLATION_READ_UNCOMMITTED    读未提交

* ISOLATION_READ_COMMITTED         读已提交

* ISOLATION_REPEATABLE_READ        可重复读

* ISOLATION_SERIALIZABLE                  串行化

2)事务传播行为

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

* read-only(是否只读):建议查询时设置为只读

* timeout(超时时间):默认值是-1,没有超时限制。如果有,以秒为单位进行设置


2.2.3 TransactionStatus

TransactionStatus 接口提供的是事务具体的运行状态。


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

 

2.2.4 实现代码

1)配置文件

<!--事务管理器交给IOC-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

2)业务层代码

@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 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.out(outUser, money);
            accountDao.in(inUser, money);
            // 提交事务
            transactionManager.commit(status);
        } catch (Exception e) {
            e.printStackTrace();
            // 回滚事务
            transactionManager.rollback(status);
        }
    }
}

2.2.5 知识小结

Spring中的事务控制主要就是通过这三个API实现的

* PlatformTransactionManager  负责事务的管理,它是个接口,其子类负责具体工作
* TransactionDefinition               定义了事务的一些相关参数
* TransactionStatus                    代表事务运行的一个实时状态

理解三者的关系:事务管理器通过读取事务定义参数进行事务管理,然后会产生一系列的事务状态

 

2.3 基于XML的声明式事务控制【重点】

在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。底层采用AOP思想来实现的。

声明式事务控制明确事项:

  •     核心业务代码(目标对象) (切入点是谁?)
  •     事务增强代码(Spring已提供事务管理器))(通知是谁?)
  •     切面配置(切面如何配置?)

 

2.3.1 快速入门

需求
使用spring声明式事务控制转账业务。
步骤分析

1. 引入tx命名空间
2. 事务管理器通知配置
3. 事务管理器AOP配置
4. 测试事务控制转账业务代码


1)引入tx命名空间

<?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
		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">

  <!--  以上引入了下面的约束   
        xmlns:tx="http://www.springframework.org/schema/tx"
		http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx.xsd -->

2)事务管理器通知配置

<!--事务管理器对象-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--通知增强-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--定义事务的一些属性 * 表示当前任意名称的方法都走默认配置-->
        <tx:attributes>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

3)事务管理器AOP配置

    <!--aop配置:配置切面, 声明式事务的配置, 下面写advisor 而不是aspect-->
    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lagou.servlet.impl.AccountServiceImpl.*(..))"/>
    </aop:config>-->

4)测试事务控制转账业务代码

package com.lagou.test;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:applicationContext.xml"})
public class AccountServiceImplTest {

    @Autowired
    private AccountSerivce accountSerivce;

    @Test
    public void testTransfer(){
        accountSerivce.transfer("tom","jerry",100d);
    }
}

 

2.3.2 事务参数的配置详解

<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED"
timeout="-1" read-only="false"/>
* name:切点方法名称
* isolation:事务的隔离级别
* propogation:事务的传播行为
* timeout:超时时间
* read-only:是否只读

CRUD常用配置

<!--事务管理器对象-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--通知增强-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--定义事务的一些属性 * 表示当前任意名称的方法都走默认配置-->
        <!--
            name: 切点方法名称
            isolation:事务的隔离级别,
            propagation:事务的传播行为
            read-only:是否只读
            timeout:超时时间 -1是没有超时时间
        -->;
        <tx:attributes>
            <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" timeout="-1"/>
            <!--**CRUD常用配置**	-->
            <!--以xxx开头的方法, 设置为后面的配置	-->
            <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>

2.3.3 知识小结

* 平台事务管理器配置

* 事务通知的配置

* 事务aop织入的配置


2.4 基于注解的声明式事务控制【重点】

2.4.1 常用注解

步骤分析

1. 修改service层,增加事务注解
2. 修改spring核心配置文件,开启事务注解支持

1)修改service层,增加事务注解

package com.lagou.servlet.impl;

@Service
@Transactional // 在这里添加注解, 则当前类所有方法都采用事务控制, 属性默认值也可
public class AccountServiceImpl implements AccountSerivce {

    @Autowired
    private AccountDao accountDao;
    
    // 下面添加这个注解, 并配置属性
    // @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ,timeout = -1,readOnly = false)
    public void transfer(String outUser, String inUser, Double money) {

        //调用dao的out及in方法
        accountDao.out(outUser,money);

        //int i = 1/0;

        accountDao.in(inUser,money);
    }
}

2)修改spring核心配置文件,开启事务注解支持

<?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
		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">

    ...

    <!--事务的注解支持-->
    <tx:annotation-driven/>

    ... 后面关于tx属性配置标签都可以注解掉

</beans>

 

2.4.2 纯注解

核心配置类

package com.lagou.config;

@Configuration  // 声明该类为核心配置类
@ComponentScan("com.lagou")  // 包扫描
@Import(DataSourceConfig.class) //导入其他配置类
@EnableTransactionManagement // 新注解, 开启事务的注解支持
public class SpringConfig {

    @Bean // 下面将DataSource对象注入 传入参数
    public JdbcTemplate getJdbcTemplate(@Autowired DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        return jdbcTemplate;
    }

    @Bean   // 使用接口类型接收实例化对象
    public PlatformTransactionManager getPlatformTransactionManager(@Autowired DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource);
        return dataSourceTransactionManager;
    }
}

数据源配置类

package com.lagou.config;

@PropertySource("classpath:jdbc.properties") //引入properties文件
public class DataSourceConfig {

    // 注入配置文件中的数据
    @Value("${jdbc.driverClassName}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    @Bean // 因为druidDataSource是jar包中的类, 没法使用component注解, 当前标签会把当前方法的返回值对象放进IOC容器中
    public DataSource getDataSource(){

        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(driver);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        return druidDataSource;
    }
}
package com.lagou.test;

@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration({"classpath:applicationContext.xml"})
// 下面替换了配置读取方式
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceImplTest {

    @Autowired
    private AccountSerivce accountSerivce;

    @Test
    public void testTransfer(){
        accountSerivce.transfer("tom","jerry",100d);
    }
}

2.4.3 知识小结

* 平台事务管理器配置(xml、注解方式)

* 事务通知的配置(@Transactional注解配置)

* 事务注解驱动的配置 <tx:annotation-driven/>、@EnableTransactionManagement


三 Spring集成web环境

3.1 ApplicationContext应用上下文获取方式

应用上下文对象是通过  new ClasspathXmlApplicationContext(spring配置文件) 方式获取的,但是每次从容器中获得Bean时都要编写  new ClasspathXmlApplicationContext(spring配置文件) ,这样的弊端是配置文件加载多次,应用上下文对象创建多次。

 

解决思路分析:
在Web项目中,可以使用ServletContextListener监听Web应用的启动,我们可以在Web应用启动时,就加载Spring的配置文件,创建应用上下文对象ApplicationContext,在将其存储到最大的域servletContext域中,这样就可以在任意位置从域中获得应用上下文ApplicationContext对象了。

 

3.2 Spring提供获取应用上下文的工具

上面的分析不用手动实现,Spring提供了一个监听器ContextLoaderListener就是对上述功能的封装,该监听器内部加载Spring配置文件,创建应用上下文对象,并存储到ServletContext域中,提供了一个客户端工具WebApplicationContextUtils供使用者获得应用上下文对象。

所以我们需要做的只有两件事:
1. 在web.xml中配置ContextLoaderListener监听器(导入spring-web坐标)
2. 使用WebApplicationContextUtils获得应用上下文对象ApplicationContext

 

3.3 实现

1)导入Spring集成web的坐标

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
    </dependencies>

2)配置ContextLoaderListener监听器

<!--全局参数:指定applciationContext.xml文件的路径-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    <!--spring的监听器 contextLoaderListenere-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

3)通过工具获得应用上下文对象

ApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());
        Account account = (Account) webApplicationContext.getBean("account");

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值