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:///spring

jdbc.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事务管理主要提供了三个接口来完成

  1. org.springframework.transaction.PlatformTransactionManager

    这是一个事务管理器,可以来选择相关的平台(jdbc hibernate jpa…)

  2. TransactionDefinition

    它定义事务的一些相关信息 例如 隔离 传播 超时 只读

  3. 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

回到顶部