前言
前面已经讲述了Spring Aop的原理以及源码分析~
若对Spring AOP还不是太了解的话,强烈建议出门左拐,先掌握AOP相关内容,因为Spring的事务管理就是基于Spring AOP实现的
本文主要讲解Spring-JDBC的使用以及它对事务的管理。
主要分为两大块:
1.Spring对jdbc的支持
2.Spring对事务的支持
源码展示基于Spring版本号为:5.1.6.RELEASE 下同下同下同
源码展示基于Spring版本号为:5.1.6.RELEASE 下同下同下同
源码展示基于Spring版本号为:5.1.6.RELEASE 下同下同下同
环境准备
Pom里导入相关jar(基于之前的工程基础上导包):
<!-- 链接数据库 此处若你的MySql是8.0+版本,请使用8.0+版本的MySql驱动程序--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <!-- 含有spring-tx/core/beans等必须包 所有spring-tx可以不用再单独导入了--> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.framework.version}</version> </dependency>
配置文件:
@Configuration public class JdbcConfig { // 此处只是为了演示 所以不用连接池了===========生产环境禁止这么使用========== @Bean public DataSource dataSource() { MysqlDataSource dataSource = new MysqlDataSource(); dataSource.setUser("root"); dataSource.setPassword("root"); dataSource.setURL("jdbc:mysql://localhost:3306/jedi"); return dataSource; } 为了执行sql方便 此处采用JdbcTemplate进行=========== // 生产环境一下一般我们不需要此配置,因为一般我们会使用ORM框架~ // 但是如果是SpringBoot,这两个类默认都会配置上(导入了Spring-JDBC的jar即可) 比如MyBatis就是基于JDBC的 @Bean public JdbcTemplate jdbcTemplate(DataSource dataSource) { return new JdbcTemplate(dataSource); } @Bean public NamedParameterJdbcTemplate namedParameterJdbcTemplate(DataSource dataSource) { return new NamedParameterJdbcTemplate(dataSource); } }
测试连接是否通畅:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {RootConfig.class, JdbcConfig.class}) public class TestSpringBean { @Autowired private DataSource dataSource; @Test public void test1() throws SQLException { System.out.println(dataSource); // com.mysql.jdbc.jdbc2.optional.MysqlDataSource@650eab8 System.out.println(dataSource.getConnection()); // com.mysql.jdbc.JDBC4Connection@72bc6553 System.out.println(jdbcTemplate); //org.springframework.jdbc.core.JdbcTemplate@66982506 System.out.println(namedParameterJdbcTemplate); //org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate@70cf32e3 } }
Spring JDBC
为了使JDBC更加易于使用,Spring 在 JDBC API 上定义了一个抽象层,以此建立一个 JDBC 存取框架
说明:
在实际开发中,我们DAO层一般都会使用ORM框架(Mybatis,hibernate)等。在有些特殊的情况下,ORM框架的搭建略显笨重(比如下面我们演示Spring事务的时候)。这时最好的选择就是Spring中的jdbcTemplate了
JdbcTemplate和NamedParameterJdbcTemplate
jdbcTemplate提供的主要方法
1.execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
2.update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;
batchUpdate方法用于执行批处理相关语句;
3.query方法及queryForXXX方法:用于执行查询相关语句;
4.call方法:用于执行存储过程、函数相关语句
Demo:
@Test public void test1() throws SQLException { String sql = "select * from user where id = ?"; // 默认情况下:它就是使用的PreparedStatement,所以不用担心Sql注入问题的 RowMapper<User> rowMapper = new BeanPropertyRowMapper<>(User.class); List<User> list = jdbcTemplate.query(sql, rowMapper, 1); User user = jdbcTemplate.queryForObject(sql, rowMapper, 1); System.out.println(list); System.out.println(user); }
NamedParameterJdbcTemplate提供的主要方法
在经典的 JDBC 用法中, SQL 参数是用占位符 ? 表示,并且受到位置的限制. 定位参数的问题在于, 一旦参数的顺序发生变化, 就必须改变参数绑定,否则就绑定错了
在 Spring JDBC 框架中, 绑定 SQL 参数的另一种选择是使用具名参数(named parameter).
具名参数: SQL 按名称(以冒号开头)而不是按位置进行指定. 具名参数更易于维护, 也提升了可读性. 具名参数由框架类在运行时用占位符取代
NamedParameterJdbcTemplate:是Spring2.0提供的,比JdbcTemplate出现得晚。它可以使用全部jdbcTemplate方法
// @since 2.0 public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations { // 它持有一个JdbcTemplate的引用,所以它能够执行它所有的方法 private final JdbcOperations classicJdbcTemplate; ... }
Demo Show:
@Test public void test1() throws SQLException { String sql = "insert into user (name,age) values (:name,:age)"; User u = new User(); u.setName("fsx2"); u.setAge(20); SqlParameterSource sqlParameterSource = new BeanPropertySqlParameterSource(u); // 不需要id使用这个方法 //namedParameterJdbcTemplate.update(sql,sqlParameterSource); // 这个可议把id输出出来 KeyHolder keyHolder = new GeneratedKeyHolder(); namedParameterJdbcTemplate.update(sql, sqlParameterSource, keyHolder); int k = keyHolder.getKey().intValue(); System.out.println(k); //2 id就为2 }
NamedParameterJdbcTemplate和JdbcTemplate有KeyHolder类,使用它我们可以获得主键,类似Mybatis中的useGeneratedKeys。
因为整体上直接使用JdbcTemplate来操作数据库的可能性几乎没有,所以此处只做一个简单的介绍,重点是后面的Spring事务的讲解~~
Spring事务
事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。
通常情况下,如果在事务中抛出了未检查异常(继承自 **RuntimeException** 的异常),则默认将回滚事务。如果没有抛出任何异常,或者抛出了已检查异常,则仍然提交事务。这通常也是大多数开发者希望的处理方式,也是 EJB 中的默认处理方式
事务(Transaction)是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。
数据库向用户提供保存当前程序状态的方法,叫事务提交(commit);当事务执行过程中,使数据库忽略当前的状态并回到前面保存的状态的方法叫事务回滚(rollback)
Spring配置文件中关于事务配置总是由三个组成部分:
1.DataSource
2.TransactionManager
3.动态代理(核心内容)
DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化。DataSource实际为SessionFactory,TransactionManager的实现为 HibernateTransactionManager(MyBatis还是使用的DataSourceTransactionManager)
Spring Framework对事务管理提供了一致的抽象,其特点如下:
- 为不同的事务API提供一致的编程模型,比如JTA(Java Transaction API), JDBC, Hibernate, JPA(Java Persistence API和JDO(Java Data Objects)
- 支持声明式事务管理,特别是基于注解的声明式事务管理,简单易用
- 提供比其他事务API如JTA更简单的编程式事务管理API
- 与spring数据访问抽象的完美集成
下面示例的事务管理器通知配置为:
@Configuration public class JdbcConfig { ... // ==============Spring事务相关配置~~~================== // 必须配置一个事务管理器:此处用的DataSourceTransactionManager来管理事务~~~ @Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource); return dataSourceTransactionManager; } ... }
业务类为:
public interface HelloService { Object hello(); } @Service public class HelloServiceImpl implements HelloService { @Autowired private JdbcTemplate jdbcTemplate; @Override public Object hello() { // 向数据库插入一条记录 String sql = "insert into user (name,age) values ('fsx',21)"; jdbcTemplate.update(sql); // 做其余的事情 可能抛出异常 System.out.println(1 / 0); return "service hello"; } }