JdbcTemplate和声明式事务控制
一、Spring JdbcTemplate
1.1、Spring JdbcTemplate简介
JdbcTemplate是Spring框架中提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装。Spring框架
为我们提供了很多的操作模板类。例如:操作关系型数据的JdbcTemplate和HibernateTemplate,操作
nosql数据库的RedisTemplate,操作消息队列的JmsTemplate等等。
类似与Apache dbutils。
1.2、使用步骤
- 导入相关Jar包;
- 创建数据库表和实体类;
- 创建JdbcTemplate对象;
- 执行CRUD操作。
1.3、快速入门在这里插入代码片
1.3.1、起步
-
导入相关Jar包
-
创建数据库表和实体类
user表
User.java
public class User {
private long id;
private String username;
private String password;
public User() {
}
public User(long id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
//get和set方法
//tostring方法
}
- Spring JdbcTemplate简单使用
public class MyTest1 {
@Test
public void test() throws PropertyVetoException {
//数据源
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//配置数据源
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUser("root");
dataSource.setPassword("123456");
System.out.println(dataSource);
//创建JdbcTemplate对象并写入datasource
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
//测试
String sql = "INSERT INTO `user`(username,`password`)VALUES(?,?)";
Object[] obj = {"111","2222"};
int result = jdbcTemplate.update(sql, obj);
System.out.println(result);
}
}
1.3.2、使用Spring管理JdbcTemplate
上面的做法是传统的方式,我们学习了Spring,可以将数据源交给Spring容器进行管理,将
JdbcTemplate交给Spring进行管理,通过依赖注入管理JdbcTemplate和数据源的关系,然后通过Spring
容器获得JdbcTemplate对象来执行操作。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--引入外部配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置jdbctemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
测试
public class MyTest2 {
private JdbcTemplate jdbcTemplate;
@Before
public void init(){
//配置初始化方法
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
jdbcTemplate = context.getBean(JdbcTemplate.class);
}
//添加
@Test
public void test1(){
String sql = "INSERT INTO `user`(username,`password`)VALUES(?,?)";
Object[] obj = {"222","2222"};
int result = jdbcTemplate.update(sql, obj);
System.out.println(result);
}
//根据id删除
@Test
public void test2(){
String sql = "DELETE FROM `user` WHERE id=?";
Object[] params = {15l};
int result = jdbcTemplate.update(sql, params);
System.out.println(result);
}
//修改用户名根据id
@Test
public void test3(){
String sql = "UPDATE `user` SET username=? WHERE id=?";
Object[] params = {"adafdafasdf",1l};
int result = jdbcTemplate.update(sql, params);
System.out.println(result);
}
@Test
public void test4(){
String sql = "SELECT * FROM `user`";
List<User> users = jdbcTemplate.query(sql, new BeanPropertyRowMapper<User>(User.class));
for (User user : users) {
System.out.println(user);
}
}
//查询所有
@Test
public void test5(){
String sql = "SELECT * FROM `user` WHERE id=?";
Object[] params = {1l};
User user1 = jdbcTemplate.queryForObject(sql, params, new BeanPropertyRowMapper<>(User.class));
System.out.println(user1);
}
//查询user表中的所有username和password
@Test
public void test6(){
String sql = "SELECT username,password FROM `user`";
//Map username:111,password:123
//把列名设成key值,列里面的数据设成value值
//因为有多行所以设成list<Map>形式
// List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
// System.out.println(maps);
// 或者
List<Map<String,Object>> map = jdbcTemplate.query(sql, new RowMapper<Map<String,Object>>() {
//映射行 行-->Map
@Override
public Map<String, Object> mapRow(ResultSet resultSet, int i) throws SQLException {
Map<String, Object> map = new HashMap<>();
map.put("username", resultSet.getObject("username"));
map.put("password", resultSet.getObject("password"));
//返回进行映射之后的对象
return map;
}
});
for (Map<String, Object> stringObjectMap : map) {
System.out.println(stringObjectMap);
}
}
//查询操作(聚合函数)
@Test
public void test7(){
String sql = "SELECT COUNT(*) FROM `user`";
Long result = jdbcTemplate.queryForObject(sql, Long.class);
System.out.println(result);
}
}
二、声明式事务控制
2.1、编程式事务控制相关对象
PlatformTransactionManager接口是Spring的事务管理器,它里面提供了我们常用的操作事务的方法
- 事务隔离级别
设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读。
ISOLATION_DEFAULT
ISOLATION_READ_UNCOMMITTED
ISOLATION_READ_COMMITTED
ISOLATION_REPEATABLE_READ
ISOLATION_SERIALIZABLE - 事务传播行为
REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务
中。一般的选择(默认值)
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
2.2、声明式事务控制
2.2.1、什么是声明式事务控制
Spring的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中
声明,用在Spring 配置文件中声明式的处理事务来代替代码式的处理事务。
声明式事务处理的作用
事务管理不侵入开发的组件。具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上
也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事
务管理策划的话,也只需要在定义文件中重新配置即可
在不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,不需改变代码
重新编译,这样维护起来极其方便
注意:Spring 声明式事务控制底层就是AOP。
2.2.2、声明式事务控制实现
声明式事务控制需要明确的一个问题:
谁是切点?
谁是通知?
配置织入?
该部分内容在《02_SpringIOC和DI案例及动态代理》3.1、基础工程搭建的基础之上进行操作,但是没
有使用JdbcUtils工具类,在Dao层使用了Spring JdbcTemplate。
2.2.2.1、引入相关命名空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
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
">
<!--引入外部文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置datasource-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--解析外部文件配置-->
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置jdbctemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--引入datasource-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置dao-->
<bean id="accountDao" class="com.hpe.dao.impl.AccountDaoImpl">
<!--引入jdbctemplate-->
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<!--目标对象 service-->
<bean id="accountService" class="com.hpe.service.impl.AccountServiceImpl">
<!--引入dao-->
<property name="accountDao" ref="accountDao"/>
</bean>
<!-- 配置平台事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--引入datasource-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--通知,事务的增强-->
<tx:advice transaction-manager="transactionManager" id="txadvice">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--织入-->
<aop:config>
<aop:pointcut id="pt" expression="execution(* com.hpe.service.impl..*.*(..))"/>
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>
</beans>
2.2.2.4、测试
public class MyTest {
@Test
public void testTrans() throws Exception {
//创建Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
//获取代理对象
IAccountService accountService = (IAccountService) context.getBean("accountService");
//转账
accountService.transfer(1, 2, 10);
}
}