欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring中的JDBCTemplate、Spring基于AOP的事务控制、Spring中的事务控制

程序员文章站 2023-03-26 14:14:27
Spring学习笔记第四天...



1.Spring中的JDBCTemplate

1.1 Spring中JDBCTemplate的概述

Spring中的JDBCTemplate、Spring基于AOP的事务控制、Spring中的事务控制
spring中JDBCTemplate是对JDBC简单封装和 commons-dbutils 类似,在使用起来也很相似。它是 spring 框架中提供的一个对象,是对原始 Jdbc API 对象的简单封装。 spring 框架为我们提供了很多的操作模板类。

功能 模板类
操作关系型数据的 JdbcTemplate、HibernateTemplate
操作 nosql 数据库的 RedisTemplate
操作消息队列的 JmsTemplate

我们今天的主角在 spring-jdbc-5.0.2.RELEASE.jar 中,我们在导包的时候,除了要导入这个 jar 包外,还需要导入一个 spring-tx-5.0.2.RELEASE.jar(它是和事务相关的)。
我们先创建一个新的Module命名为day04_01jdbcTemplate,首先修改pom.xml导入项目需要的jar包。

<?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.itheima</groupId> <artifactId>day04_01jdbcTemplate</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</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>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> </dependencies> </project> 

然后我们准备一张数据库表,这个表我们之前的学习中已经创建过了,

DROP TABLE IF EXISTS `account`; CREATE TABLE `account` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `money` float NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; INSERT INTO `account` VALUES (1, 'aaa', 800); INSERT INTO `account` VALUES (2, 'bbb', 2100); 

然后在创建com.itheima.domain包并创建这个表的实体类Account.java

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

下面就来演示一下Spring中JDBCTemplate最简单的使用方式,在创建一个com.itheima.jdbctemplate包,并且在其中创建一个JdbcTemplateDemo1.java。

/**
 * JdbcTemplate 的最基本用法
 */ public class JdbcTemplateDemo1 { public static void main(String[] args) { // 准备数据源:Spring的内置数据源 DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql://localhost:3306/spring"); ds.setUsername("root"); ds.setPassword("123456"); //1.创建JdbcTemplate对象 JdbcTemplate jt = new JdbcTemplate(); //给jt设置数据源 jt.setDataSource(ds); //2.执行操作 jt.execute("insert into account(name, money) values ('ddd', 1000)"); } } 

这个Module的完整结构如下。
Spring中的JDBCTemplate、Spring基于AOP的事务控制、Spring中的事务控制

我们先来插查看一下数据库中的数据如下。
Spring中的JDBCTemplate、Spring基于AOP的事务控制、Spring中的事务控制
然后我们来运行下这个main方法。运行完成之后我们在来看一下数据库表的变化。数据库表如下,说名运行成功了
Spring中的JDBCTemplate、Spring基于AOP的事务控制、Spring中的事务控制
我们在来看一下这个main方法里的代码,发现数据库连接的参数都是写死的,而且对象是new出来的,如果你学过前面的知识你会马上想到使用ioc来配置

1.2 JDBCTemplate在Spring IOC中的使用:

通过对上面的代码分析,我们可以对上面的代码进行一定的优化,下面我们就使用IOC来重新配置一下。首先在resources里新建一个bean.xml文件,来配置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"> <!--配置JdbcTemplate--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!--配置数据源--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/spring"></property> <property name="username" value="root"></property> <property name="password" value="123456"></property> </bean> </beans> 

然后我们把JdbcTemplateDemo1.java拷贝一份,复制到和JdbcTemplateDemo1.java同一个包下命名为JdbcTemplateDemo2.java。

public class JdbcTemplateDemo2 { public static void main(String[] args) { //1.获取IOC容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.根据id获取bean对象 JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate"); //3.执行操作 jt.execute("insert into account(name, money) values ('ccc', 2222)"); } } 

然后我们来执行一个这个main方法,通过查看数据库表的变化,发现这样也是可以正常运行的。

1.3 JDBCTemplate的CRUD操作

下面我们就来学习一下JDBCTemplate的CRUD操作。我们把JdbcTemplateDemo2.java复制一份放到和JdbcTemplateDemo2.java相同的目录下命名为JdbcTemplateDemo3.java。CRUD的具体操作请看下面的代码。

/**
 * JdbcTemplate 的CRUD操作
 */ public class JdbcTemplateDemo3 { public static void main(String[] args) { //1.获取IOC容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.根据id获取bean对象 JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate"); //3.执行操作 //保存 // jt.update("insert into account(name, money) values (?,?)", "eee", 3333f); //更新 //jt.update("update account set name = ?, money = ? where id = ?", "test", 4567f, 7); //删除 //jt.update("delete from account where id = ?", 5); //查询所有,使用 我们自定义Account的封住策略 //        List<Account> accounts = jt.query("select * from account where money > ?;", new AccountRowMapper(), 1000f); //使用Spring为我们提供的封住策略 //        List<Account> accounts = jt.query("select * from account where money > ?;", new BeanPropertyRowMapper<Account>(Account.class), 1000f); //        System.out.println(Arrays.toString(accounts)); //查询一个 //        List<Account> accounts = jt.query("select * from account where id = ?;", new BeanPropertyRowMapper<Account>(Account.class), 1); //        System.out.println(accounts.isEmpty() ? "没有内容" : accounts.get(0)); //查询返回一行一列(使用聚合函数,但不加group by句子) Long count = jt.queryForObject("select count(*) from account where money > ?", Long.class, 1000f); // 避免返回值大于Integer的最大值,所以使用Long System.out.println(count); } } /**
 * 定义Account的封住策略
 */ class AccountRowMapper implements RowMapper<Account> { /**
     * 把结果集中的数据封装到Account中,然后Spring把每个Account加到集合中
     *
     * @param resultSet
     * @param i
     * @return
     * @throws SQLException
     */ 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.getFloat("money")); //使用反射设置属性值 ResultSetMetaData rsmd = resultSet.getMetaData(); // 通过ResultSetMetaData获取结果集中的列数 int columnCount = rsmd.getColumnCount(); for (int j = 0; j < columnCount; j++) { try { // 获取每个列的列名 String columName = rsmd.getColumnName(j + 1); Field field = Account.class.getDeclaredField(columName); field.setAccessible(true); // 获取每个列的列值 Object columValue = resultSet.getObject(j + 1); // field.set(account, columValue); field.set(account, resultSet.getObject(columName)); } catch (Exception e) { e.printStackTrace(); } } return account; } } 

1.4 JDBCTemplate在DAO中的使用

既然我们要说 JDBCTemplate在Dao中的使用,那么首先我们要在com.itheima.dao包里创建一个IAccountDao.java的接口

/**
 * 账户的持久层接口
 */ public interface IAccountDao { /**
     * 根据id查询账户
     *
     * @param accountId
     * @return
     */ Account findAccountById(Integer accountId); /**
     * 根据名称查询账户
     *
     * @param accountName
     * @return
     */ Account findAccountByName(String accountName); /**
     * 更新账户信息
     *
     * @param account
     */ void updateAccount(Account account); } 

然后在com.itheima.dao.impl包里创建一个IAccountDao的实现类AccountDaoImpl.java

/**
 * 账户的持久层实现类
 */ public class AccountDaoImpl implements IAccountDao { private JdbcTemplate jdbcTemplate; // 用于使用Spring进行数据注入 public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public Account findAccountById(Integer accountId) { List<Account> accounts = jdbcTemplate.query("select * from account where id = ?", new BeanPropertyRowMapper<Account>(Account.class), accountId); return accounts.isEmpty() ? null : accounts.get(0); } public Account findAccountByName(String accountName) { List<Account> accounts = jdbcTemplate.query("select * from account where name = ?", new BeanPropertyRowMapper<Account>(Account.class), accountName); if (accounts.isEmpty()) { return null; } if (accounts.size() > 1) { throw new RuntimeException("结果集不唯一"); } return accounts.get(0); } public void updateAccount(Account account) { jdbcTemplate.update("update account set name = ?, money = ? where id = ?", account.getName(), account.getMoney(), account.getId()); } } 

还有就是我们需要配置一下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="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> ... </beans> 

下面我们就可以来创建测试类写测试方法来测试我们的代码了,和上面一样=简单起见我们复制一下JdbcTemplateDemo2.java,复制到相同的包下命名为JdbcTemplateDemo4.java。

/**
 * JdbcTemplate 的最基本用法
 */ public class JdbcTemplateDemo4 { public static void main(String[] args) { //1.获取IOC容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.根据id获取bean对象 IAccountDao accountDao = (IAccountDao) ac.getBean("accountDao"); //3.执行操作 Account account = accountDao.findAccountById(1); System.out.println(account); account.setMoney(10000f); //执行更新操作 accountDao.updateAccount(account); } } 

我们运行一下上面的代码可以正常运行,但是如果我们还有其他的IAccountDao实现类呢?每个类都要写 private JdbcTemplate jdbcTemplate; 这样就会有重复代码。怎么办呢?往下看。

1.4 JdbcDaoSupport的使用以及Dao的两种编写方式

对于上面提到的多个Dao的实现类都要写 private JdbcTemplate jdbcTemplate; 的问题,我们可以把重复的代码提取出来放到父类中,然后各个Dao的实现类都基础自实现类。下面我们就来写一个Dao实现类的父类JdbcDaoSupport.java

/**
 * 此类用于抽取 dao 中的重复代码
 */ public class JdbcDaoSupport { private JdbcTemplate jdbcTemplate; // 用于使用Spring进行数据注入 public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public JdbcTemplate getJdbcTemplate() { return jdbcTemplate; } public void setDataSource(DataSource dataSource) { if (jdbcTemplate == null) { jdbcTemplate = createJdbcTemplate(dataSource); } } private JdbcTemplate createJdbcTemplate(DataSource dataSource) { return new JdbcTemplate(dataSource); } } 

然后我们在复制一个AccountDaoImpl.java到相同的包下命名为AccountDaoImpl2.java
让其集成自JdbcDaoSupport

/**
 * 账户的持久层实现类
 * 这个版本适合使用xml配置,因为继承了 JdbcDaoSupport 这个是Spring提供的不方便使用注解
 */ public class AccountDaoImpl2 extends JdbcDaoSupport implements IAccountDao { public Account findAccountById(Integer accountId) { // 使用父类中的JdbcTemplate List<Account> accounts = super.getJdbcTemplate().query("select * from account where id = ?", new BeanPropertyRowMapper<Account>(Account.class), accountId); return accounts.isEmpty() ? null : accounts.get(0); } public Account findAccountByName(String accountName) { List<Account> accounts = super.getJdbcTemplate().query("select * from account where name = ?", new BeanPropertyRowMapper<Account>(Account.class), accountName); if (accounts.isEmpty()) { return null; } if (accounts.size() > 1) { throw new RuntimeException("结果集不唯一"); } return accounts.get(0); } public void updateAccount(Account account) { super.getJdbcTemplate().update("update account set name = ?, money = ? where id = ?", account.getName(), account.getMoney(), account.getId()); } } 

然后修改一下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"> <!--配置账户的持久层 改成 AccountDaoImpl2--> <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl2"> <!--<property name="jdbcTemplate" ref="jdbcTemplate"></property>--> <!--只需要注入DataSource就行了,因位会触发创建JdbcTemplate的方法--> <property name="dataSource" ref="dataSource"></property> </bean> <!--配置JdbcTemplate--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!--配置数据源--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/spring"></property> <property name="username" value="root"></property> <property name="password" value="123456"></property> </bean> </beans> 

然后创建一个测试类JdbcTemplateDemo4.java

/**
 * JdbcTemplate 的最基本用法
 */ public class JdbcTemplateDemo4 { public static void main(String[] args) { //1.获取IOC容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.根据id获取bean对象 IAccountDao accountDao = (IAccountDao) ac.getBean("accountDao"); //3.执行操作 Account account = accountDao.findAccountById(1); System.out.println(account); account.setMoney(30000f); //执行更新操作 accountDao.updateAccount(account); } } 

运行一下测试类JdbcTemplateDemo4中的main方法,可以发现仍然可以正常运行。这时我们把我们写的这个JdbcDaoSupport.java删除掉,会发现AccountDaoImpl2.java中会自动导入 org.springframework.jdbc.core.support.JdbcDaoSupport 因为我们写的这个父类Spring都已经给我准备好了。我们在运行一下测试方法,可以发现仍然可以正常运行。
这两种Dao的实现方法都可以正常使用,第一种 不继承JdbcDaoSupport的Dao实现类适合使用注解配置IOC第二种基础自JdbcDaoSupport的Dao实现类适合使用XML配置IOC

2.Spring基于AOP的事务控制

3.Spring中的事务控制

本文地址:https://blog.csdn.net/Code_Boy_Code/article/details/108017510