模板技术
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{@Autowiredprivate 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.编写sqlString sql = "select * from car";//4.获取执行sql的stmt对象stmt=conn.prepareStatement(sql);//5.执行sqlrs = 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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://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 {@Autowiredprivate JdbcTemplate jdbcTemplate;/*** 测试的方式*/@Testpublic 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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://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 {@Overridepublic void outMoney(String out, double money) {this.getJdbcTemplate().update("update account set money = money - ? where name = ?",money, out);}@Overridepublic 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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://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 {@Autowiredprivate 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使用