spring jdbc及事务管理
本文内容纲要:spring jdbc及事务管理
Spring提供了一个jdbc模板,它类似于dbutils工具。
快速入门
创建数据库
CREATE DATABASE springtest;USE springtest;
CREATE TABLE t_user(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
age INT,
sex VARCHAR(20)
)
INSERT INTO t_user VALUES(NULL,'tom',20,'男');
INSERT INTO t_user VALUES(NULL,'fox',30,'男');
INSERT INTO t_user VALUES(NULL,'tony',40,'男');
SELECT * FROM t_user;
C3P0开源连接池配置
<!-- 配置连接池对象 --> <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="jdbc:mysql:///spring"></property>
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>
为了便于修改
引入外部属性文件,在src下的db.properties文件
jdbc.jdbcUrl=jdbc:mysql:///springjdbc.driverClass=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=root
在applicationContext.xml文件中引入
<context:property-placeholder location="classpath:db.properties"/>
所以C3P0连接池的引入可以改为
<!-- 配置c3p0连接池 --> <bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
在自己配置中需要从properties文件中引入的信息可以使用${name}方式来获取
JdbcTemplate CRUD
执行insert update delete操作
只需要使用JdbcTemplate的update方法就可以执行insert update delete操作
@Autowired @Qualifier("jdbcTemplate")
private JdbcTemplate template;
@Test
public void test1() {
// update执行update操作
template.update("update t_user set name = ? where id = ?", "猥琐逼", 1);
}
@Test
public void test2() {
// update执行update操作
template.update("insert into t_user values(null,?,?,?)", "龟哥", 25, "男");
}
@Test
public void test3() {
// update执行delete操作
template.update("delete from t_user where id = ?", 4);
}
执行select操作
简单数据返回
/* * 下面测试查询语句返回简单的数据类型
*/
@Test
public void test4() {
String name = template.queryForObject("select name from t_user where id = 1", String.class);
System.out.println(name);
}
@Test
public void test5() {
Integer count = template.queryForObject("select count(*) from t_user", Integer.class);
System.out.println(count);
}
复杂数据返回
/* * 下面测试复杂返回类型
*/
@Test
public void test6() {
// 如果返回的是一个对象,可以使用queryForObject方法
User user = template.queryForObject("select * from t_user where id = ?", new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int arg1) throws SQLException {
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setAge(rs.getInt("age"));
user.setSex(rs.getString("sex"));
return user;
}
},1);
System.out.println(user);
}
@Test
public void test7() {
// 如果返回的是一个集合,使用query方法
List<User> list = template.query("select * from t_user", new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int arg1) throws SQLException {
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setAge(rs.getInt("age"));
user.setSex(rs.getString("sex"));
return user;
}
});
System.out.println(list);
}
注意:如果只返回一个domain对象,可以使用queryForObject方法,如果返回的是List<?>对象,
可以使用query方法,但是都需要使用RowMapper来对ResultSet进行处理。
RowMapper它有一个实现类叫BeanPropertyRowMapper
如果使用BeanPropertyRowmapper,实体类必须提供一个无参数的public构造方法,类中的bean属性名称与表中的列要对应
@Test public void test8() {
// 使用rowMapper的实现类BeanPropertyRowMapper
/*List<User> list = template.query("select * from t_user", new BeanPropertyRowMapper<User>(User.class));
System.out.println(list);*/
List<User> user = template.query("select * from t_user where id = 1", new BeanPropertyRowMapper<User>(User.class));
System.out.println(user);
}
spring的事务管理
下面通过一个转账案例来了解spri
创建数据库表
CREATE TABLE account( id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
money DOUBLE
)
INSERT INTO account VALUES(NULL,'tom',1000);
INSERT INTO account VALUES(NULL,'fox',1000);
创建service于dao
@Service("accountService")public class AccountServiceImpl implements AccountService{
@Autowired
@Qualifier("accountDao")
private AccountDaoImpl ad;
@Override
public void account(String outname, String inname, double money) {
ad.accountIn(inname,money);
//int a = 10 /0;
ad.accountOut(outname,money);
}
}
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao{
@Autowired
@Qualifier("jdbcTemplate")
private JdbcTemplate temple;
@Override
public void accountIn(String inname, double money) {
temple.update("update account set money = money + ? where name = ?",money,inname);
}
@Override
public void accountOut(String outname, double money) {
temple.update("update account set money = money - ? where name = ?",money,outname);
}
}
不要忘了在applicationContext中配置开启注解
<!-- 开启注解配置 --> <context:component-scan base-package="com.learn"></context:component-scan>
如果打开//int a = 10 /0;
就一定会排出异常
这时我们就需要事务控制,让事务具有一致性
Spring事务管理主要提供了三个接口来完成
- org.springframework.transaction.PlatformTransactionManager
这是一个事务管理器,可以来选择相关的平台(jdbc hibernate jpa…)
- TransactionDefinition
它定义事务的一些相关信息 例如 隔离 传播 超时 只读
- TransactionStatus
它主要描述事务具体的运行状态
PlatformTransactionManager:
平台事务管理器,在不同的持久化层解决技术它的事务代码不一样。
DataSourceTransactionManager 主要针对于JdbcTemplate开发 MyBatis开发
HibernateTransactionManasger主要针对于Hibernate开发
JpaTransactionManager 主要针对于JPA开发。
TransactionDefinition:
它描述的是事务的定义信息。
在TransactionDefinition中定义了大量的常量
事务的四个特性 ACID 原子性 一致性 隔离性 持久性。
不考虑事务隔离性会出现:脏读,不可重复读 虚读。
ISOLATION_DEFUALT 它使用后端数据库的默认隔离级别(spring中选项)
ISOLATION_READ_UNCOMMITTED 不能解决问题,会发生脏读 不可重复读 虚读
ISOLATION_READ_COMMITTED 可以解决脏读 会产生不可重复读与虚读。
ISOLATION_REPEATABLE_READ 可以解决脏读,不可重复读 解决不了虚读
ISOLATION_SERIALIZABLE 串行化,可以解决所有问题
对于不现的数据库,它的底层默认事务隔离级别不一样。
Oracle数据库它默认的是read_committed
Mysql数据库它默认的是repeatable_read.
下面再介绍一下它的传播特性:
它解决的是两个被事务管理的方法互相调用问题。它与数据库没关系,是程序内部维护的问题。
最常用的三种:
PROPAGATION_REQUIRED 默认值 两个操作处于同一个事务,如果之前没有事务,新建一个事务
PROPAGATION_REQUIRES_NEW,两个操作处于不同的事务
PROPAGATION_NESTED,它是一种嵌套事务,它是使用SavePoint来实现的。
事务回滚时可以回滚到指定的savepoint,注意:它只对DataSourceTransactionManager有作用
TransactionStatus:
它定义了事务状态信息,在事务运行过程中,得到某个时间点的状态
事务管理方式
1. 编码方案 不建议使用,它具有侵入性。在原有的业务代码基础上去添加事务管理代码
2. 声明式事务控制,基于AOP对目标进行代理,添加around环绕通知。
这种方案,它不具有侵入性,不需要修改原来的业务代码
基于xml配置声明式事务管理方案
<!-- 配置开启事务 --> <!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="c3p0DataSource"></property>
</bean>
<!-- 配置通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- name:必须的,对哪些方法进行事务控制 isolation 可选 设置事务隔离级别 默认是DEFAULT propagation:可选
设置事务传播 默认值 REQUIRED timeout 可选 超时时间 默认值-1 read-only 可选 默认值是false 如果不是只读,它可以对insert
update delete操作,如果是只读不可以。 rollback-for 可选 可以设置一个异常,如果产生这个异常,触发事务回滚 no-rolback-for
可选 可以设置一个异常,如果产生这个异常,不会触发事务回滚 -->
<tx:method name="account" />
</tx:attributes>
</tx:advice>
<!-- 配置切面 -->
<aop:config>
<aop:pointcut
expression="execution(* com.learn.service.AccountService.account(..))"
id="txPointcut" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
</aop:config>
基于annotation声明式事务管理方案
<!-- 开启注解配置事务 --> <tx:annotation-driven transaction-manager="transactionManager"/>
在需要开启的类或方法上声明
@Transactional
本文内容总结:spring jdbc及事务管理
原文链接:https://www.cnblogs.com/learnjfm/p/7141775.html
以上是 spring jdbc及事务管理 的全部内容, 来源链接: utcz.com/z/362736.html