spring入门实战&源码解读(3):spring JdbcTemplate和事务

一、JdbdTemplate基本使用

Spring的JDBC模块负责数据库资源和错误处理,大大简化了开发人员对数据库的操作,使得开发人员可以从繁琐的数据库操作中解脱出来,从而将更多的精力投入到编写业务逻辑中。

1.1JdbcTemplate基本使用概述

针对数据库的操作,Spring框架提供的一个JdbcTemplate类对象,是对原始繁琐的jdbc api的封装,是Spring框架数据抽象层的基础,其他更高层次的抽象是构建于JdbcTemplate类之上的,可以说JdbcTemplate类是Spring JDBC的核心类。Spring框架为我们提供了很多操作的模板类。例如操作关系型数据库的JdbcTemplate和HibernateTemplate,操作nosql数据库的RedisTemplate等等。JdbcTemplate对象创建的源码如下:

public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
	private static final String RETURN_RESULT_SET_PREFIX = "#result-set-";
    private static final String RETURN_UPDATE_COUNT_PREFIX = "#update-count-";
    private boolean ignoreWarnings = true;
    private int fetchSize = -1;
    private int maxRows = -1;
    private int queryTimeout = -1;
    private boolean skipResultsProcessing = false;
    private boolean skipUndeclaredResults = false;
    private boolean resultsMapCaseInsensitive = false;


	public JdbcTemplate() {
	    }
	
	    public JdbcTemplate(DataSource dataSource) {
	        this.setDataSource(dataSource);
	        this.afterPropertiesSet();
	    }
	
	    public JdbcTemplate(DataSource dataSource, boolean lazyInit) {
	        this.setDataSource(dataSource);
	        this.setLazyInit(lazyInit);
	        this.afterPropertiesSet();
	    }
	public void setDataSource(@Nullable DataSource dataSource) {
	        this.dataSource = dataSource;
	    }
	}    

从上述源码可以看出,JdbcTemplate类的直接父类是JdbcAccessor,该类提供了一些访问数据库时使用的公共属性,除了默认构造参数之外,都需要提供一个数据源DataSource,DataSource的主要功能是获取数据库连接,具体实现可以引入对数据库连接的缓冲池和分布式事务支持。既然JdbcTemplate中有set方法,那我们可以先在配置文件中配置这些对象,然后通过依赖注入的方式来配置这些对象。

1.2JdbcTemplate基本使用的开发步骤

1.2.1导入spring-jdbc坐标和spring-tx坐标

<?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>
    <packaging>jar</packaging>

    <groupId>com.itheima</groupId>
    <artifactId>itheima_spring_jdbc</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.2.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.7</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.9.RELEASE</version>
        </dependency>

    </dependencies>

</project>

1.2.2 创建Account实体类对象

public class Account implements Serializable{
    private Integer id;
    private String name;
    private Double money;

    public Integer getId() {
        return id;
    }

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

    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;
    }
}

1.2.3 在spring配置文件中配置数据源以及JdbcTemplate

<?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="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis"></property>
        <property name="user" value="root"></property>
        <property name="password" value="Shezeq1,"></property>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="datasource"></property>
    </bean>
</beans>

1.2.4JdbcTemplate的增删改查操作

  • 最基本的使用execute(),execute(String sql)方法能够完成执行SQL语句的功能。而update()方法能够完成插入、更新和删除数据的操作。
public class JdbcTemplateDemo1 {
    public static void main(String[] args) {
        //1.获取Spring容器
        ApplicationContext ac =  new ClassPathXmlApplicationContext("bean.xml");
        //2.根据id获取bean对象
        JdbcTemplate jdbcTemplate = (JdbcTemplate) ac.getBean("jdbcTemplate");
        //3.执行操作
        jdbcTemplate.execute("insert  into account(name,money) values('吉姆巴特勒',200.34)");
    }
}

  • 保存操作
public class JdbcTemplateDemo1 {
    public static void main(String[] args) {
        //1.获取Spring容器
        ApplicationContext ac =  new ClassPathXmlApplicationContext("bean.xml");
        //2.根据id获取bean对象
        JdbcTemplate jdbcTemplate = (JdbcTemplate) ac.getBean("jdbcTemplate");
        //3.执行操作
//        jdbcTemplate.execute("insert  into account(name,money) values('吉姆巴特勒',200.34)");
        //保存
        jdbcTemplate.update("insert  into account(name,money) values(?,?)","格林",234);
    }
}
  • 更新操作
public class JdbcTemplateDemo1 {
    public static void main(String[] args) {
        //1.获取Spring容器
        ApplicationContext ac =  new ClassPathXmlApplicationContext("bean.xml");
        //2.根据id获取bean对象
        JdbcTemplate jdbcTemplate = (JdbcTemplate) ac.getBean("jdbcTemplate");
        //3.执行操作
//        jdbcTemplate.execute("insert  into account(name,money) values('吉姆巴特勒',200.34)");
        //保存
        //jdbcTemplate.update("insert  into account(name,money) values(?,?)","格林",234);
        //更新操作
        jdbcTemplate.update("update account set name=?,money=? where id=?","小岛川龙井",666.777,5);
    }
}

  • 删除操作
public class JdbcTemplateDemo1 {
    public static void main(String[] args) {
        //1.获取Spring容器
        ApplicationContext ac =  new ClassPathXmlApplicationContext("bean.xml");
        //2.根据id获取bean对象
        JdbcTemplate jdbcTemplate = (JdbcTemplate) ac.getBean("jdbcTemplate");
        //3.执行操作
//        jdbcTemplate.execute("insert  into account(name,money) values('吉姆巴特勒',200.34)");
        //保存
        //jdbcTemplate.update("insert  into account(name,money) values(?,?)","格林",234);
        //更新操作
//        jdbcTemplate.update("update account set name=?,money=? where id=?","小泽玛丽亚",666.777,5);
        //删除操作
        jdbcTemplate.update("delete from account where id=?",5);
    }
}
  • 查询所有
package com.itheima.jdbcTemplate;

import com.itheima.domain.Account;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

public class JdbcTemplateDemo1 {
    public static void main(String[] args) {
        //1.获取Spring容器
        ApplicationContext ac =  new ClassPathXmlApplicationContext("bean.xml");
        //2.根据id获取bean对象
        JdbcTemplate jdbcTemplate = (JdbcTemplate) ac.getBean("jdbcTemplate");
        //3.执行操作
//        jdbcTemplate.execute("insert  into account(name,money) values('吉姆巴特勒',200.34)");
        //保存
        //jdbcTemplate.update("insert  into account(name,money) values(?,?)","格林",234);
        //更新操作
//        jdbcTemplate.update("update account set name=?,money=? where id=?","小泽玛丽亚",666.777,5);
        //删除操作
//        jdbcTemplate.update("delete from account where id=?",5);
        List<Account> accounts = jdbcTemplate.query("select * from account where money>?", new AccountRowMapper(), 500);
        for (Account account:accounts){
            System.out.println(account);
        }

    }
}

class AccountRowMapper implements RowMapper<Account> {
    @Override
    public Account mapRow(ResultSet resultSet, int i) throws SQLException {
        Account account = new Account();
        account.setId(resultSet.getInt("id"));
        account.setName(resultSet.getString("name"));
        account.setMoney(resultSet.getDouble("money"));
        return account;
    }
}
  • 查询一个(根据id查询)
package com.itheima.jdbcTemplate;

import com.itheima.domain.Account;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

public class JdbcTemplateDemo1 {
    public static void main(String[] args) {
        //1.获取Spring容器
        ApplicationContext ac =  new ClassPathXmlApplicationContext("bean.xml");
        //2.根据id获取bean对象
        JdbcTemplate jdbcTemplate = (JdbcTemplate) ac.getBean("jdbcTemplate");
        //3.执行操作
//        jdbcTemplate.execute("insert  into account(name,money) values('吉姆巴特勒',200.34)");
        //保存
        //jdbcTemplate.update("insert  into account(name,money) values(?,?)","格林",234);
        //更新操作
//        jdbcTemplate.update("update account set name=?,money=? where id=?","小泽玛丽亚",666.777,5);
        //删除操作
//        jdbcTemplate.update("delete from account where id=?",5);
//        List<Account> accounts = jdbcTemplate.query("select * from account where money>?", new AccountRowMapper(), 500);
//        for (Account account:accounts){
//            System.out.println(account);
//        }
        //查询一个
        List<Account> accounts = jdbcTemplate.query("select * from account where id=?", new AccountRowMapper(), 6);
        System.out.println(accounts.isEmpty()?"没有结果":accounts.get(0));
    }
}

class AccountRowMapper implements RowMapper<Account> {
    @Override
    public Account mapRow(ResultSet resultSet, int i) throws SQLException {
        Account account = new Account();
        account.setId(resultSet.getInt("id"));
        account.setName(resultSet.getString("name"));
        account.setMoney(resultSet.getDouble("money"));
        return account;
    }
}
  • 查询返回一行一列
public class JdbcTemplateDemo1 {
    public static void main(String[] args) {
        //1.获取Spring容器
        ApplicationContext ac =  new ClassPathXmlApplicationContext("bean.xml");
        //2.根据id获取bean对象
        JdbcTemplate jdbcTemplate = (JdbcTemplate) ac.getBean("jdbcTemplate");
        //3.执行操作
//        jdbcTemplate.execute("insert  into account(name,money) values('吉姆巴特勒',200.34)");
        //保存
        //jdbcTemplate.update("insert  into account(name,money) values(?,?)","格林",234);
        //更新操作
//        jdbcTemplate.update("update account set name=?,money=? where id=?","小泽玛丽亚",666.777,5);
        //删除操作
//        jdbcTemplate.update("delete from account where id=?",5);
//        List<Account> accounts = jdbcTemplate.query("select * from account where money>?", new AccountRowMapper(), 500);
//        for (Account account:accounts){
//            System.out.println(account);
//        }
        //查询一个
//        List<Account> accounts = jdbcTemplate.query("select * from account where id=?", new AccountRowMapper(), 6);
//        System.out.println(accounts.isEmpty()?"没有结果":accounts.get(0));
        //查询返回一行一列的操作
        Integer total = jdbcTemplate.queryForObject("select count(*) from account where money>?", Integer.class, 500);
        System.out.println(total);
    }

}

class AccountRowMapper implements RowMapper<Account> {
    @Override
    public Account mapRow(ResultSet resultSet, int i) throws SQLException {
        Account account = new Account();
        account.setId(resultSet.getInt("id"));
        account.setName(resultSet.getString("name"));
        account.setMoney(resultSet.getDouble("money"));
        return account;
    }
}

1.3在dao中使用JdbcTemplate

1.3.1准备实体类

package com.itheima.domain;

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

    public Integer getId() {
        return id;
    }

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

    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;
    }
}

1.3.2在dao中定义JdbcTemplate

package com.itheima.dao.impl;

import com.itheima.dao.IAccountDao;
import com.itheima.domain.Account;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.List;

public class IAccountDaoImpl implements IAccountDao {
    public void setJt(JdbcTemplate jt) {
        this.jt = jt;
    }

    //
    private JdbcTemplate jt;

    @Override
    public List<Account> findAll() {

        List<Account> accounts =  jt.query("select * from account",new AccountRwoMapper());
        return accounts;
    }

    @Override
    public Account findAccountById(Integer id) {
        List<Account> accounts = jt.query("select * from account where id=?",new AccountRwoMapper(),id);
        return accounts.get(0);
    }

    @Override
    public Account findAccountByName(String name) {
        List<Account> accounts = jt.query("select * from account where name =?",new AccountRwoMapper(),name);
        return accounts.get(0);
    }

    @Override
    public void saveAccount(Account account) {
        jt.update("insert into account(name,money) values(?,?)",account.getName(),account.getMoney());
    }

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

    @Override
    public void deleteAccount(Integer id) {
        jt.update("delete from account where id =?",id);
    }
}

1.3.3在spring主配置文件bean.xml中加入相关配置

<?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="iAccountDao" class="com.itheima.dao.impl.IAccountDaoImpl">
        <property name="jt" ref="jt"></property>
    </bean>
    <bean id="jt" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="datasource"></property>
    </bean>
    <bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis"></property>
        <property name="user" value="root"></property>
        <property name="password" value="Shezeq1,"></property>
    </bean>
</beans>

二、声明式事务控制

2.1编程式事务控制相关对象

2.1.1PlateformTransactionManager

PlatformTransactionManager接口是Spring的平台事务管理器,主要用于管理事务,它里面提供了我们常用的操作事务的方法。

方法说明
TransactionStatus getTransaction(TransactionDefination defination)获取事务状态信息
void commit(TransactionStatus status)提交事务
void rollback(TransactionStatus status)回滚事务

上面的三个方法中,getTransaction(TransactionDefination defination)方法会根据TransactionDefination参数返回一个TransactionDefination对象,TransactionDefination对象表示一个事务,它被关联在当前执行的线程上。注意:PlatformTransactionManager是接口类型的,不同的Dao层技术有不同的实现类,例如:Dao层技术是jdbc或者mybatis时,实现的接口是org.springframework.jdbc.datasource.DataSourceTransactionManager。Dao层技术是hibernate时:org.springframework.orm.hibernate5.HibernateTransactionManager。

2.1.2TransactionDefination

TransactionDefination是事务的定义信息抽象,该对象中定义了事务的规则,并提供了获取事务相关信息的方法,具体如下:

方法说明
String getName()获取事务对象的名称
int getIsolationLevel()获得事务的隔离级别
int getPropogationBehavior()获得事务的传播行为
int getTimeOut()获取超时时间
boolean isReadOnly()是否只读

上述方法中,事务的传播行为是指在同一个方法中,不同操作前后所使用的事务。具体的传播如下:

  • REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的
    选择(默认值)。比如在实际开发过程中,业务层的A业务方法调用B业务方法,B业务方法看A业务方法当前有没有事务,如果B业务方法看A业务方法没有事务,那么B业务方法就新建一个事务,
  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
  • MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
  • REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。
  • NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
  • NEVER:以非事务方式运行,如果当前存在事务,抛出异常
  • NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作
  • 超时时间:默认值是-1,没有超时限制。如果有,以秒为单位进行设置
  • 是否只读:建议查询时设置为只读

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

  • ISOLATION_DEFAULT
  • ISOLATION_READ_UNCOMMITTED
  • ISOLATION_READ_COMMITTED
  • ISOLATION_REPEATABLE_READ
  • ISOLATION_SERIALIZABLE
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值