spring框架:简述JdbcTemplate及事务控制

本人小白一枚,欢迎大家一起讨论学习,如有错误,还望大家指教。

简述JdbcTemplate

JdbcTemplate概述
它是spring框架中提供的一个对象,是对原始JDBC API对象的简单封装。spring框架为我们提供了很多操作模板类。操作关系型数据库的JdbcTemplate和HibernateTemplate,操作nosql数据库的RedisTemplate以及操作消息队列的JmsTemplate。
JdbcTemplate对象的创建
spring框架:简述JdbcTemplate及事务控制_第1张图片
配置常见的几种数据源

  • 配置C3P0数据源
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
     <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
     <property name="url" value="jdbc:mysql:///frame?characterEncoding=utf-8"/>
     <property name="username" value="root"/>
     <property name="password" value="root"/>
</bean>
  • 配置DBCP数据源
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
     <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
     <property name="url" value="jdbc:mysql:///frame?characterEncoding=utf-8"/>
     <property name="username" value="root"/>
     <property name="password" value="root"/>
</bean>
  • 配置Druid数据源
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
     <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
     <property name="url" value="jdbc:mysql:///frame?characterEncoding=utf-8"/>
     <property name="username" value="root"/>
     <property name="password" value="root"/>
</bean>
  • 配置spring内置数据源:spring框架提供了一个内置数据源,我们也可以使用这个,它存在于spring-jdbc-5.0.2.REEASE.jar 包中。
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
     <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
     <property name="url" value="jdbc:mysql:///frame?characterEncoding=utf-8"/>
     <property name="username" value="root"/>
     <property name="password" value="root"/>
</bean>

JdbcTemplate使用案例

  • 创建一个名为frame数据库,并在其中添加account数据表,表结构如下所示。
    spring框架:简述JdbcTemplate及事务控制_第2张图片
  • 创建一个maven工程,并在其pom文件添加如下坐标。
<dependencies>
        <!--spring核心坐标-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--spring jdbc坐标-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--数据库连接驱动坐标-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <!--添加单元测试坐标-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
  • 创建entity包,并在其中添加账户实体类,即Account类。
/**
 * 账户的实体类
 */
public class Account implements Serializable {
    
    private Integer id;
    private String name;
    private Float 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 Float getMoney() {
        return money;
    }

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

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}
  • 创建dao包,并在其添加接口以及实现类,在接口主要添加几个简单的增删改查方法。
public interface AccountDao {
    /**
     * 保存账户信息
     * @param account 待保存的账户实体
     */
    void saveAccount(Account account);

    /**
     * 通过主键删除账户信息
     * @param id 待删除账户主键
     */
    void deleteById(int id);

    /**
     * 修改账户信息
     * @param account 修改账户实体
     */
    void updateAccount(Account account);

    /**
     * 通过账户主键查询账户信息
     * @param id 账户主键
     * @return
     */
    Account findById(int id);

    /**
     * 查询所有账户信息
     * @return
     */
    List<Account> findAll();

    /**
     * 查询账户的总个数
     * @return
     */
    int getTotal();
}
public class AccountDaoImpl implements AccountDao {

    private JdbcTemplate template;

    public void setTemplate(JdbcTemplate template) {
        this.template = template;
    }

    @Override
    public void saveAccount(Account account) {
        template.update("INSERT INTO account(name, money) VALUES(?, ?) ", account.getName(), account.getMoney());
    }

    @Override
    public void deleteById(int id) {
        template.update("DELETE FROM account WHERE id = ?", id);
    }

    @Override
    public void updateAccount(Account account) {
        template.update("UPDATE account SET name = ?, money = ? WHERE id = ?", account.getName(), account.getMoney(), account.getId());
    }

    @Override
    public Account findById(int id) {
        List<Account> accounts = template.query("SELECT * FROM account WHERE id = ?", new BeanPropertyRowMapper<Account>(Account.class), id);
        return accounts.isEmpty() ? null : accounts.get(0);
    }

    @Override
    public List<Account> findAll() {
        List<Account> accounts = template.query("SELECT * FROM account", new BeanPropertyRowMapper<Account>(Account.class));
        return accounts.isEmpty() ? null : accounts;
    }

    @Override
    public int getTotal() {
        return template.queryForObject("SELECT count(*) FROM account", Integer.class);
    }
}
  • 在resorces路径下添加spring配置文件,这里数据源的基本信息引用的是外部properties文件,所以也要创建一个dp.properties文件用来配置连接的基本信息。
    spring框架:简述JdbcTemplate及事务控制_第3张图片
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="accountDao" class="dao.impl.AccountDaoImpl">
        <property name="template" ref="jdbcTemplate"/>
    </bean>

    <!--配置JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--引入外部属性文件-->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:db.properties"/>
    </bean>
    <!--配置数据源,这里使用的是spring内置的数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
</beans>
  • 创建test包,用来添加测试代码,这里就不对一下测试代码的结果进行详细阐述了。
public class JdbcTemplateDemo {

    private AccountDaoImpl accountDao;
    
    @Before
    public void init() {
        // 注册容器
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        accountDao = context.getBean("accountDao", AccountDaoImpl.class);
    }

    /**
     * 用来测试保存方法
     */
    @Test
    public void saveTest() {
        Account account  = new Account();
        account.setName("刘灰灰");
        account.setMoney(1000f);
        accountDao.saveAccount(account);
    }

    /**
     * 用来删除方法
     */
    @Test
    public void deleteByIdTest() {
        accountDao.deleteById(1);
    }

    /**
     * 用来测试修改方法
     */
    @Test
    public void updateTest() {
        Account account = new Account();
        account.setMoney(10000f);
        account.setName("刘灰灰");
        account.setId(5);
        accountDao.updateAccount(account);
    }

    /**
     * 用来测试单个查找方法
     */
    @Test
    public void findByIdTest() {
       accountDao.findById(5);
    }

    /**
     * 用来测试查找全部方法
     */
    @Test
    public void getTotalTest() {
        System.out.printf("一共有%d个账户信息\n", accountDao.getTotal());
    }
}
  • 工程结构如下所示
    spring框架:简述JdbcTemplate及事务控制_第4张图片

总结: 引入外部数据库连接的属性文件有两种方法,一种是我们上面所演示的,使用标签注入PropertyPlaceholderConfigurer对象,另一种方式是使用。还有一个问题就是,在持久层的实现类中,如果我们dao有很多时,我们需要为每一个dao添加一个JdbcTemplate的属性,如何解决这个问题呢?解决办法:spring框架为我们提供了一个类,就是JdbcDaoSupport,该类中定义了一个JdbcTemplate对象,我们可以直接获取是使用,但是要想创建该对象,需要为其提供一个数据源,使用的方法就是我们dao实现类直接继承该类就OK。那我们在开发中使用哪种方式好呢?看具体情况而定,如果我们在dao类中自己定义JdbcTemplate,适合所有配置方式(xml和注解都可以)。如果我们让dao类继承JdbcDaoSupport,就只能基于xml方法,无法使用注解。
在这里插入图片描述
spring框架:简述JdbcTemplate及事务控制_第5张图片

Spring中的事务控制

概述: spring事务控制我们要明确的几点,第一就是JavaEE体系进行分层开发,事务处理位于业务层,Spring提供了业务层事务处理解决的方案。第二就是spring框架我们提供了一组事务控制的接口,这组接口存在于spring-tx这个jar包中。第三个就是spring事务控制都是基于AOP的,它既可以使用编程的方式,也可以使用配置的方式实现。
简述spring中事务控制API
PlatformTransactionManager接口,此接口是 spring 的事务管理器,它里面提供了我们常用的操作事务的方法,如下图
spring框架:简述JdbcTemplate及事务控制_第6张图片
开发中都是使用该接口实现类,使用以下这两种:

  • org.springframework.jdbc.datasource.DataSourceTransactionManager:使用Spring JDBC或iBatis进行持久化数据时使用。
  • org.springframework.orm.hibernate5.HibernateTransactionManager:使用Hibernate版本进行持久化数据时使用。

TransactionDefinition接口,该接口里面有如下方法:
spring框架:简述JdbcTemplate及事务控制_第7张图片
事务的隔离级别
spring框架:简述JdbcTemplate及事务控制_第8张图片
事务的传播行为
spring框架:简述JdbcTemplate及事务控制_第9张图片
事务的超时时间:默认值是-1,没有超时限制。如果有,以秒为单位进行设置。
是否是只读事务:建议查询时设置为只读,增删改时设置为可读可写。
TransactionStatus接口:该接口提供的是事务具体的运行状态,具体方法如下图:
spring框架:简述JdbcTemplate及事务控制_第10张图片
基于XML的声明式事务控制

  • 创建一个maven工程,并在pom文件添加如下内容
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.9</version>
        </dependency>
    </dependencies>
  • 创建entity包,并创建账户实体类
/**
 * 账户的实体类
 */
public class Account implements Serializable {

    private Integer id;
    private String name;
    private Float 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 Float getMoney() {
        return money;
    }

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

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}
  • 创建dao包,并添加持久层接口以及实现类。注意:这里实现类是继承JdbcTemplate的方式
public interface AccountDao {

    /**
     * 修改账户信息
     * @param account 修改账户实体
     */
    void updateAccount(Account account);

    /**
     * 通过账户名称查询账户信息
     * @param name 账户名称
     * @return
     */
    Account findByName(String name);

    /**
     * 查询所有账户信息
     * @return
     */
    List<Account> findAll();
}
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

    @Override
    public void updateAccount(Account account) {
        getJdbcTemplate().update("UPDATE account SET name = ?, money = ? WHERE id = ?", account.getName(), account.getMoney(), account.getId());
    }

    @Override
    public Account findByName(String name) {
        List<Account> accounts = getJdbcTemplate().query("SELECT * FROM account WHERE name = ?", new BeanPropertyRowMapper<Account>(Account.class), name);
        return accounts.isEmpty() ? null : accounts.get(0);
    }

    @Override
    public List<Account> findAll() {
        List<Account> accounts = getJdbcTemplate().query("SELECT * FROM account", new BeanPropertyRowMapper<Account>(Account.class));
        return accounts.isEmpty() ? null : accounts;
    }
}
  • 创建service包,并添加业务层接口以及实现类。
public interface AccountService {
    /**
     * 转账操作
     */
    void transfer(String sourceName, String targeName, Float money);
}
public class AccountServiceImpl implements AccountService {

    private AccountDao dao;

    public void setDao(AccountDao dao) {
        this.dao = dao;
    }

    @Override
    public void transfer(String sourceName, String targeName, Float money) {
        // 1.根据名称查询两个账户
        Account source = dao.findByName(sourceName);
        Account target = dao.findByName(targeName);
        // 2.修改两个账户的金额
        // 转出账户减钱
        source.setMoney(source.getMoney() - money);
        // 转入账户加钱
        target.setMoney(target.getMoney() + money);
        // 3.更新两个账户
        dao.updateAccount(source);
        int i=1/0;
        dao.updateAccount(target);
    }
}
  • 创建spring配置文件名为bean.xml,并且创建数据库连接属性的文件db.properties。
    spring框架:简述JdbcTemplate及事务控制_第11张图片
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.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">


    <!--配置Service-->
    <bean id="accountService"  class="service.impl.AccountServiceImpl">
        <property name="dao" ref="accountDao"/>
    </bean>
    <!--配置Dao-->
    <bean id="accountDao" class="dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--引入外部属性文件-->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:db.properties"/>
    </bean>
    <!--配置数据源,这里使用的是spring内置的数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--配置事务管理器-->
    <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="*" read-only="false" propagation="REQUIRED"/>
            <tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
        </tx:attributes>
    </tx:advice>
    <!--配置aop-->
    <aop:config>
        <!--配置切点表达式-->
        <aop:pointcut id="pt1" expression="execution(* service.impl.*.*(..))"/>
        <!--配置切点表达式和事务通知的对应关系-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/>
    </aop:config>
</beans>
  • 创建controller包,并添加测试类。
public class Demo {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        AccountService service = context.getBean("accountService", AccountService.class);
        service.transfer("周星星", "刘灰灰", 500f);
    }
}

spring框架:简述JdbcTemplate及事务控制_第12张图片

总结: 这里主要使用xml配置的方式实现对事物的控制,现在我们可以总结一下事物配置的配置步骤。

  • 配置事务管理器:这里需要我们依赖注入一个数据源。
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
  • 配置事务的通知引用事务管理器
<tx:advice id="txAdvice" transaction-manager="transactionManager">
</tx:advice>
  • 配置事务的属性:在tx:advice标签内部配置事务的属性。
    spring框架:简述JdbcTemplate及事务控制_第13张图片
<tx:attributes>
     <tx:method name="*" read-only="false" propagation="REQUIRED"/>
     <tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
</tx:attributes>
  • 配置AOP切入点表达式
<aop:config>
    <!--配置切点表达式-->
    <aop:pointcut id="pt1" expression="execution(* service.impl.*.*(..))"/>
</aop:config>
  • 配置切入点表达式和事务通知对应的关系:在aop:config标签内部。
  <!--配置切点表达式和事务通知的对应关系-->
  <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/>

基于注解的事务控制

  • 因为这个案例与前面那个大致相同,所以重复的过程就不在过多叙述,首先创建maven工程,在pom文件添加坐标,之后添加实体类略过。
  • 分析上面xml方式配置事务控制时,我们需要配置的是我们要对哪些类的那些方法进行什么类型的通知,而使用注解就不用那么麻烦,我们直接在业务层中我们需要的类上进行声明即可,使用@Transactional注解。
    spring框架:简述JdbcTemplate及事务控制_第14张图片

spring框架:简述JdbcTemplate及事务控制_第15张图片

  • 在配置文件中,我们需要开启spring对注解事务的支持
    在这里插入图片描述
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                     http://www.springframework.org/schema/beans/spring-beans.xsd
                     http://www.springframework.org/schema/aop
                     http://www.springframework.org/schema/aop/spring-aop.xsd
                     http://www.springframework.org/schema/tx
                     http://www.springframework.org/schema/tx/spring-tx.xsd
                     http://www.springframework.org/schema/context
                     http://www.springframework.org/schema/context/spring-context.xsd">

    <!--配置spring创建容器时要扫描的包-->
    <context:component-scan base-package="service, dao"/>

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

    <!--引入外部属性文件-->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:db.properties"/>
    </bean>
    <!--配置数据源,这里使用的是spring内置的数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--开启spring对注解事务的支持-->
    <tx:annotation-driven  transaction-manager="transactionManager"/>
</beans>

你可能感兴趣的:(框架)