模板技术
Spring框架中提供了很多模板类来简化编程,使用模板类编写程序会变的简单
持久层模板JdbcTemplate
JdbcTemplate是什么
JDBCTemplate是Spring Framework中的一个核心类,用于简化JDBC(Java数据库连接)代码的编写。它提供了一种更简单、更干净的方式来执行数据库操作,同时抽象了许多常见的数据库任务,如连接管理、异常处理和资源释放。使用JDBCTemplate,开发人员可以更专注于业务逻辑,而不必担心底层数据库操作的细节。
JDBCTemplate和Mybatis的区别
1. JDBCTemplate相当于Spring框架自带的Mybatis的弱化版,mybatis支持声明式事务管理,JDBCTemplate则不支持;
-
mybatis是一种ORM模型,JDBCTemplate则是对连接池的直接封装,本质上是纯SQL;
-
mybatis由于实体关系映射,实际的性能会比JDBCTemplate低一些,但是更加灵活
参考文章:
【Java 进阶篇】深入了解JDBCTemplate:简化Java数据库操作
弃用MyBatis!我们最终选择了 JDBCTemplate!
JdbcTemplate实战
0. maven依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</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.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</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>
</dependencies>
1. JdbcTemplate相比于原生的DataSource的优势:简写代码
1.1 连接池DataSource代码实例
这是原生的连接池DataSource
@Repository("carDao")
public class CarDaoImpl implements CarDao{
@Autowired
private DataSource dataSource;
public List<Car> findAll() {
Connection conn=null;
PreparedStatement stmt = null;
ResultSet rs = null;
List<Car> carList=new ArrayList<Car>();
//2.获取连接对象
try{
conn = dataSource.getConnection();
//3.编写sql
String sql = "select * from car";
//4.获取执行sql的stmt对象
stmt=conn.prepareStatement(sql);
//5.执行sql
rs = stmt.executeQuery();
//6.遍历结果集
while(rs.next()){
//实体类 account的实体类
Car car = new Car();
car.setId(rs.getInt("id"));
car.setCarName(rs.getString("car_name"));
car.setSize(rs.getInt("size"));
car.setColor(rs.getString("color"));
// 存储
carList.add(car);
}
//7.关闭
conn.close();
stmt.close();
rs.close();
}catch (Exception e){
e.printStackTrace();
}
System.out.println("持久层:操作数据库保存订单");
return carList;
}
获取连接,创建执行对象,编写sql,执行sql,遍历sql执行结果,关闭资源一步都不能少
1.2 new方式创建JdbcTemplate
先创建连接池对象,然后再创建JdbcTemplate对象
/**
* 使用new对象方式完成
*/
public void test(){
// 创建连接池对象,Spring框架内置了连接池对象
DriverManagerDataSource dataSource = new DriverManagerDataSource();
// 设置4个参数
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///spring_db");
dataSource.setUsername("root");
dataSource.setPassword("root");
// 提供模板,创建对象
JdbcTemplate template = new JdbcTemplate(dataSource);
// 完成数据的增删改查
template.update("insert into account values (null,?,?)","熊大",1000);
}
1.3 控制反转,依赖注入的方式创建JdbcTemplate的bean对象(使用Spring框架来管理模板类)
先创建连接池dataSource的bean对象,再将这个bean对象依赖注入JdbcTemplate的bean对象中
<?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: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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置连接池-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql:///spring_db" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!--配置jdbc模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
使用时直接autowired即可
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:applicationContext_jdbc.xml")
public class Demo1_1 {
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 测试的方式
*/
@Test
public void run1(){
jdbcTemplate.update("insert into account values (null,?,?)","熊二",500);
}
}
2. JdbcTemplate的多种导入方式
2.1 一般的三种方式
<?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: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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--导入DataSource的bean对象或者JdbcTemplate的bean对象到bean容器中-->
<!--1. 导入DataSource的bean对象-->
<!--1.1 导入Spring框架内置的连接池-->
<bean id="dataSource11" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis_demo"/>
<property name="username" value="root"/>
<property name="password" value="980708"/>
</bean>
<!--1.2 导入使用开源连接池druid-->
<bean id="dataSource12" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis_demo"/>
<property name="username" value="root"/>
<property name="password" value="980708"/>
</bean>
<!--
PropertyPlaceholderConfigurer是PlaceholderConfigurerSupport的
一个子类,用来解析${…} 占位符的,可以使用setLocation和setProperties
设置系统属性和环境变量。-->
<!--1.3.1 加载属性的文件,进而解析${…}占位符-->
<bean id="placeholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:druid.properties"/>
</bean>
<!--1.3.2 第二种写法:使用提供标签的方式-->
<context:property-placeholder location="classpath:druid.properties"/>
<!--1.3 使用加载属性的文件配置druid连接池-->
<bean id="dataSource13" 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>
<!--2.1 使用模板,Spring框架内置的连接池-->
<bean id="jdbcTemplate1" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource11"/>
</bean>
<!--2.2 使用模板,开源连接池druid配置jdbc模板-->
<bean id="jdbcTemplate2" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource12"/>
</bean>
<!--2.3 使用模板,开源连接池druid的配置文件加载jdbc模板-->
<bean id="jdbcTemplate3" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource13"/>
</bean>
</beans>
导入连接池对象的方式有多种,所以注入dataSource给JdbcTemplate对象时的方式也就有许多种
最推荐的还是读取.properties文件/.yml文件的方式,最为灵活
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis_demo?serverTimezone=UTC
jdbc.username=root
jdbc.password=980708
<?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: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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--1.3.1 加载属性的文件,进而解析${…}占位符-->
<bean id="placeholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:druid.properties"/>
</bean>
<!--1.3.2 第二种写法:使用提供标签的方式-->
<context:property-placeholder location="classpath:druid.properties"/>
<!--1.3 使用加载属性的文件配置druid连接池-->
<bean id="dataSource13" 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>
<!--2.3 使用模板,开源连接池druid的配置文件加载jdbc模板-->
<bean id="jdbcTemplate3" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource13"/>
</bean>
</beans>
2.2 简写的形式
<!--配置dao1-->
<bean id="accountDao" class="com.qcby.mySpring04.mapper.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<!--2. Dao的第二种使用方式-->
<!--区别在于:
1. 不需要导入jdbcTemplate的bean对象;
2. dao的bean对象依赖注入从jdbcTemplate对象改为dataSource,
但是需要daoImpl继承JdbcDaoSupport类
-->
<!--配置service-->
<bean id="accountDao2" class="com.qcby.mySpring04.mapper.impl.AccountDaoImpl2">
<property name="dataSource" ref="dataSource"/>
</bean>
我们可以发现,第二种形式的dao不需要注入JdbcTemplate,而是直接注入dataSource即可,但是DaoImpl的实现稍有不同
import org.springframework.jdbc.core.support.JdbcDaoSupport;
public class AccountDaoImpl2 extends JdbcDaoSupport implements AccountDao {
@Override
public void outMoney(String out, double money) {
this.getJdbcTemplate().update("update account set money = money - ? where name = ?",
money, out);
}
@Override
public void inMoney(String in, double money) {
this.getJdbcTemplate().update("update account set money = money - ? where name = ?",
money, in);
}
}
需要额外继承JdbcDaoSupport父类
3. JdbcTemplate可以直接与Spring自带的事务管理集成
相比于正常的AOP,两个都是Spring的亲儿子,所以可以少写很多代码,比如AOP配置类不用写
PlatformTransactionManager接口是平台事务管理器。该接口有具体的实现类,根据不同的持久层框架,需要选择不同的实现类!
接口方法如下:
void commit(TransactionStatus status)
void rollback(TransactionStatus status)
-
如果使用的Spring的JDBC模板或者MyBatis框架,需要选择DataSourceTransactionManager实现类
-
如果使用的是Hibernate的框架,需要选择HibernateTransactionManager实现类
3.1 xml文件配置Spring框架声明式事务管理
不需要我们自己写切面类,也不需要我们自己写增强的方法,Spring帮我们做好了
JdbcTemplate模板,dataSource,还有dao和service的bean导入略
<?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: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/context
http://www.springframework.org/schema/context/spring-context.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">
<!--配置平台事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!--Spring自带的事务切面通知管理-->
<!--配置事务的通知(没有自己编写切面类,通知方法也不是自己编写,Spring框架提供的)-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--对pay进行增强,设置隔离级别,传播行为,超时的时间-->
<tx:method name="pay" isolation="DEFAULT" propagation="REQUIRED" />
<tx:method name="find*" read-only="true" />
</tx:attributes>
</tx:advice>
<!--配置AOP的增强-->
<aop:config>
<!--Spring框架提供系统通知,使用advisor标签-->
<aop:advisor advice-ref="txAdvice"
pointcut="execution( * com.qcby.*.service.impl.*ServiceImpl.*(..))" />
</aop:config>
<import resource="ApplicationContext_jdbc.xml"/>
</beans>
3.2 半注解的配置Spring框架声明式事务管理
<!--配置平台事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!--开启事务注解的支持-->
<tx:annotation-driven transaction-manager="transactionManager" />
@Transactional可以加在类上,也可以加在方法上
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, timeout = 10)
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
/**
* 转账方法
*
* @param out 付款人
* @param in 收款人
* @param money 金额
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void pay(String out, String in, double money) {
// 调用dao方法
accountDao.outMoney(out, money);
accountDao.inMoney(in, money);
}
}
3.3 全注解
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
@Configuration
@ComponentScan(basePackages="cn.qcby")
@EnableTransactionManagement // 开启事务注解
public class SpringTransactionConfig {
/**
* @return
* @throws Exception
*/
@Bean(name="dataSource")
public DataSource createDataSource() throws Exception{
// 创建连接池对象,Spring框架内置了连接池对象
DriverManagerDataSource dataSource = new DriverManagerDataSource();
// 设置4个参数
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///spring_db");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
/**
* 创建模板对象
* @return
*/
@Resource(name="dataSource") // 不仅可以作用在属性上,也可以作用方法上。
@Bean(name="jdbcTemplate") // 把JdbcTemplate保存到IOC容器中
public JdbcTemplate createJdbcTemplate(DataSource dataSource){
JdbcTemplate template = new JdbcTemplate(dataSource);
return template;
}
/**
* 创建平台事务管理器对象
* @param dataSource
* @return
*/
@Resource(name="dataSource")
@Bean(name="transactionManager")
public PlatformTransactionManager createTransactionManager(DataSource dataSource){
DataSourceTransactionManager manager = new DataSourceTransactionManager(dataSource);
return manager;
}
@Resource注解是依赖注入的注解,根据name唯一查找bean
@Autowired也是依赖注入的注解,但是@Autowired只能根据类型注入
所以@Autowired一般和@Controller,@Component,@Service,@Repository配合使用
而@Resource一般和@Bean使用