一、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