1. Spring JdbcTemplate
1.1 概述
JdbcTemplate是spring框架中提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装。
1.2 JdbcTemplate基本使用
①导入spring-jdbc和spring-tx坐标
②创建数据库表和实体
③创建JdbcTemplate对象
④执行数据库操作
导入坐标
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.3.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.2.3.RELEASE</version></dependency>
创建数据库实体

创建对象,然后执行操作
public class SpringJDBCTest {@Testpublic void jdbctest() throws Exception {// 创建数据源ComboPooledDataSource dataSource = new ComboPooledDataSource();dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/springlearn?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8");dataSource.setUser("root");dataSource.setPassword("root");JdbcTemplate jdbcTemplate = new JdbcTemplate();// 设置数据源,知道数据库在哪jdbcTemplate.setDataSource(dataSource);// 执行操作int update = jdbcTemplate.update("insert into Person values (?,?,?)", "zhangsan", 18, "dongguan");}}
1.3 JdbcTemplate基本使用-Spring管控
将JdbcTemplate的创建权交给Spring,将数据源DataSource的创建权也交给Spring,在Spring容器内部将数据源DataSource注入到JdbcTemplate模版对象中,然后通过Spring容器获得JdbcTemplate对象来执行操作。
配置spring管控JdbcTemplate和DataSource
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><!-- 参数的name 跟类的set方法对应 也就是set方法命名然后去掉set首字母小写--><property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property><property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springlearn?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8"></property><property name="user" value="root"></property><property name="password" value="root"></property></bean><!-- 创建JDBC模板对象--><bean id="JDBCTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean>
编码测试代码
// Spring管理和创建JDBCTemplate对象@Testpublic void jdbctest1(){ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");JdbcTemplate jdbcTemplate = (JdbcTemplate) app.getBean("JDBCTemplate");int update = jdbcTemplate.update("insert into Person values (?,?,?)", "lisi", 18, "guanzhou");System.out.println(update);}
将填写内容抽取
<!--加载配置文件--><context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder><!--创建数据源--><bean id="dataProPSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><!-- 参数的name 跟类的set方法对应 也就是set方法命名然后去掉set首字母小写--><!-- 用${}来取加载进配置文件的值--><property name="driverClass" value="${jdbc.driver}"></property><property name="jdbcUrl" value="${jdbc.url}"></property><property name="user" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!-- 创建JDBC模板对象--><bean id="JDBCTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataProPSource" ref="dataProPSource"></property></bean>
其他数据库操作
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class SpringJDBCTest {@Autowiredprivate JdbcTemplate jdbcTemplate;@Testpublic void jdbctestcud(){int insert = jdbcTemplate.update("insert into Person values (?,?,?)", "wangwu", 18, "guizhou");int delet = jdbcTemplate.update("delete from Person where name =?", "lisi");int update = jdbcTemplate.update("update Person set age =? where name =?", 30,"wangwu");}//查询全部@Testpublic void jdbctestqall(){List<Person> person = jdbcTemplate.query(("select * from Person"), new BeanPropertyRowMapper<Person>(Person.class));System.out.println(person);}//单条查询@Testpublic void jdbctestqone(){Person person = jdbcTemplate.queryForObject(("select * from Person where name =?"), new BeanPropertyRowMapper<Person>(Person.class), "zhangsan");System.out.println(person);}// 聚合查询@Testpublic void jdbctestqcount(){Integer count = jdbcTemplate.queryForObject(("select count(*) from Person"), Integer.class);System.out.println(count);}}
2. 声明式事务控制
编程式事务控制相关对象介绍:
2.1 PlatformTransactionManager
PlatformTransactionManager 接口是 spring 的事务管理器,它里面提供了我们常用的操作事务的方法。

注意:
PlatformTransactionManager 是接口类型,不同的 Dao 层技术则有不同的实现类。
例如:
Dao 层技术是jdbc 或 mybatis 时:org.springframework.jdbc.datasource.DataSourceTransactionManager
Dao 层技术是hibernate时:org.springframework.orm.hibernate5.HibernateTransactionManager
2.2 TransactionDefinition
TransactionDefinition 是事务的定义信息对象,具体常用方法如下。

2.2.1 事务隔离级别
设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读。
ISOLATION_DEFAULT
ISOLATION_READ_UNCOMMITTED
ISOLATION_READ_COMMITTED
ISOLATION_REPEATABLE_READ
ISOLATION_SERIALIZABLE
2.2.2 事务传播行为
REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)**
MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
NEVER:以非事务方式运行,如果当前存在事务,抛出异常
NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作
超时时间:默认值是-1,没有超时限制。如果有,以秒为单位进行设置
是否只读:建议查询时设置为只读
2.3 TransactionStatus
TransactionStatus 接口提供的是事务具体的运行状态,方法如下。

3. 声明式事务控制
3.1 什么是声明式事务控制
Spring 的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中声明,用在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。
声明式事务处理的作用:
事务管理不侵入开发的组件。具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策划的话,也只需要在定义文件中重新配置即可
在不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,无需改变代码重新编译,这样维护起来极其方便
注意:Spring 声明式事务控制底层就是AOP。
3.2 基于 XML 的声明式事务控制实现
声明式事务控制明确事项:
谁是切点?
谁是通知?
配置切面?
dao层
//接口public interface ShopDao {public void out(String outname,double prices);public void in(String inname,double prices);}//实现类public class ShopDaoImpl implements ShopDao {private JdbcTemplate jdbcTemplate;public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}public void out(String outname, double prices) {jdbcTemplate.update("update shop set prices =prices-? where name =?",prices,outname);}public void in(String inname, double prices) {jdbcTemplate.update("update shop set prices =prices+? where name =?",prices,inname);}}
service层
//接口public interface ShopService {public void transfer(String inname,String outname,double prices);}//实现类public class ShopServiceImpl implements ShopService {private ShopDao shopDao;public void setShopDao(ShopDao shopDao) {this.shopDao = shopDao;}public void transfer(String inname, String outname, double prices) {// 开启事务shopDao.in(inname,prices);int i =1/0; //自定义错误 测试事务控制shopDao.out(outname,prices);// 提交事务}}
配置文件让Spring容器管控
<?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"><!--加载配置文件--><!-- <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>--><!-- <bean id="dataProPSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">--><!-- <!– 参数的name 跟类的set方法对应 也就是set方法命名然后去掉set首字母小写–>--><!--<!– 用${}来取加载进配置文件的值–>--><!-- <property name="driverClass" value="${jdbc.driver}"></property>--><!-- <property name="jdbcUrl" value="${jdbc.url}"></property>--><!-- <property name="user" value="${jdbc.username}"></property>--><!-- <property name="password" value="${jdbc.password}"></property>--><!-- </bean>--><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><!-- 参数的name 跟类的set方法对应 也就是set方法命名然后去掉set首字母小写--><property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property><property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springlearn?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8"></property><property name="user" value="root"></property><property name="password" value="root"></property></bean><!-- 创建JDBC模板对象--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean><!-- 配置ShopDao--><bean id="shopDao" class="com.joyfullyone.dao.impl.ShopDaoImpl"><property name="jdbcTemplate" ref="jdbcTemplate"></property></bean><!-- 配置ShopService--><bean id="shopService" class="com.joyfullyone.service.impl.ShopServiceImpl"><property name="shopDao" ref="shopDao"></property></bean><!-- 告诉spring使用哪种平台技术--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!-- 配置通知 也就是增强类--><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="*"/></tx:attributes></tx:advice><!-- 配置事务aop织入--><aop:config><!-- 事务增强使用advisor--><aop:advisor advice-ref="txAdvice" pointcut="execution(* com.joyfullyone.service.impl.*.*(..))"></aop:advisor></aop:config></beans>
测试
public class ShopController {public static void main(String[] args) {ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");ShopService shopService = (ShopService) app.getBean("shopService");shopService.transfer("lisi","zhangsan",10);}}
3.2.1 切点方法的事务参数的配置
具体参数可以看上一小点的具体属性
<!-- 配置通知 也就是增强类 事务的增强--><tx:advice id="txAdvice" transaction-manager="transactionManager"><!-- 设置事务的属性--><tx:attributes><!-- 设置哪些方法增强事务name 就是需要事务增强的方法名称(切点方法名称)isolation:事务的隔离级别propogation:事务的传播行为timeout:超时时间read-only:是否只读--><tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED" timeout="-1" read-only="false"/><tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED" timeout="-1" read-only="false"/><tx:method name="*" /></tx:attributes></tx:advice>
3.3 基于注解的声明式事务控制实现
配置包扫描和开启事务
<!--组件扫描--><context:component-scan base-package="com.joyfullyone"/><!-- 告诉spring使用哪种平台技术--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!--事务的注解驱动--><tx:annotation-driven transaction-manager="transactionManager"/><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><!-- 参数的name 跟类的set方法对应 也就是set方法命名然后去掉set首字母小写--><property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property><property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springlearn?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8"></property><property name="user" value="root"></property><property name="password" value="root"></property></bean><!-- 创建JDBC模板对象--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean>
dao层用注解实现
//接口public interface ShopDao {public void out(String outname,double prices);public void in(String inname,double prices);}//实现@Repository("shopDao")public class ShopDaoImpl implements ShopDao {@Autowiredprivate JdbcTemplate jdbcTemplate;public void out(String outname, double prices) {jdbcTemplate.update("update shop set prices =prices-? where name =?",prices,outname);}public void in(String inname, double prices) {jdbcTemplate.update("update shop set prices =prices+? where name =?",prices,inname);}}
service层注解实现
//接口public interface ShopService {public void transfer(String inname,String outname,double prices);}//实现@Service("shopService")public class ShopServiceImpl implements ShopService {@Autowiredprivate ShopDao shopDao;// public void setShopDao(ShopDao shopDao) {// this.shopDao = shopDao;// }@Transactionalpublic void transfer(String inname, String outname, double prices) {// 开启事务shopDao.in(inname,prices);int i =1/0;shopDao.out(outname,prices);// 提交事务}}
3.3.1 注解配置声明式事务控制解析
①使用 @Transactional 在需要进行事务控制的类或是方法上修饰,注解可用的属性同 xml 配置方式,例如隔离级别、传播行为等。
②注解使用在类上,那么该类下的所有方法都使用同一套注解参数配置。
③使用在方法上,不同的方法可以采用不同的事务参数配置。
④Xml配置文件中要开启事务的注解驱动<tx:annotation-driven />





