8.Spring + JDBC + 事务(注解)
来源:互联网 发布:淘宝宝贝销售规格 编辑:程序博客网 时间:2024/06/05 10:42
这次,讲述的是如题,Spring+JDBC+事务(注解)。因为涉及到数据库的操作,所以顺道
把事务注解一起述说了,因为很简单。
数据源的配置、配置事务管理器(Spring中配置事务bean)和开启事务注解:
beans_4.xml:
<?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/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <!-- classpath:jdbc.properties表示类路径(src包)下的jdbc.properties --> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <bean id="dataSource" class="${dataSource}" destroy-method="close"> <property name="driverClassName" value="${driverClassName}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> <!-- 连接池启动时的初始值 --> <property name="initialSize" value="${initialSize}"/> <!-- 连接池的最大值 --> <property name="maxActive" value="${maxActive}"/> <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分 一直减少到maxIdle为止 --> <property name="maxIdle" value="${maxIdle}"/> <!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 --> <property name="minIdle" value="${minIdle}"/> </bean> <!-- 扫描com.zyy下所有子包的类 --> <context:component-scan base-package="com.zyy"></context:component-scan> <!-- 配置事务bean --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 开启事务注解 --> <tx:annotation-driven transaction-manager="txManager"/></beans>
数据源的配置就是按照那个配置格式修改就可以了。
配置事务bean利用到了spring对jdbc的事务支持。
开启事务注解就一句话:<tx:annotation-driven transaction-manager="txManager"/>
xml中的value值采用了资源文件的形式存储在jdbc.properties:
dataSource = org.apache.commons.dbcp.BasicDataSourcedriverClassName = org.gjt.mm.mysql.Driverurl = jdbc:mysql://localhost:3306/ceshi_1?useUnicode=true&characterEncoding=UTF-8username = rootpassword = rootinitialSize = 1maxActive = 500maxIdle = 2minIdle = 1
配置一个bean,来执行事务和数据库操作。PersonServiceBean_6:
package com.zyy.service.impl;import com.zyy.dao.Person;import com.zyy.service.PersonService_6;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Propagation;import org.springframework.transaction.annotation.Transactional;import javax.annotation.PostConstruct;import javax.sql.DataSource;import java.sql.Types;import java.util.List;/** * Created by CaMnter on 2014/8/22. *//** * @Transactional 事务注解 可以表示 这个bean下执行每一个方法的前都会打开失误 执行后都会关闭失误 * * 假如一个方法有多条sql语句 那么都会在一个事务内 ,不加注解则在不同的事务中执行 * @Transactional(noRollbackFor = Exception.class) Exception异常不回滚 这样即使有异常也执行Sql * @Transactional(rollbackFor = Exception.class) Exception异常回滚 有Exception异常 不执行 * * * 事务如果有异常 不处理 都会回滚 不执行sql * 如果有异常 处理了 不回滚 继续执行 这两点可以利用以上的特性修改 * @Transactional(propagation=Propagation.NOT_SUPPORTED) 表示不经过事务管理 被标注的方法不会开启事务 * * 事务的传播属性 * (80%使用)REQUIRED:业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到该事务 * 否则为自己创建一个新的事务。 * * NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开启事务。如果方法在一个事 * 务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行。 * * REQUIRESNEW:属性表明不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中 * 则原有事务会被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先的事务才会恢复 * 执行。 * * MANDATORY:该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果业务方法在 * 没有事务的环境下调用,容器就会抛出例外。 * * SUPPORTS:这一事务属性表明,如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分。如果业务方法在 * 事务范围外被调用,则方法在没有事务的环境下执行。 * * Never:指定业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,容器会抛出例外,只有业务方法没 * 有关联到任何事务,才能正常执行。 * * NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按REQUIRED属性执行.它使用了 * 一个单独的事务, 这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对 * DataSourceTransactionManager事务管理器起效 * * * 如果一个类标注了事务@Transactional * * 那么它的每一个方法都是默认标注了 @Transactional(propagation = Propagation.REQUIRED) * @Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly = true) 只读事务 一般读取数据的时候用 * 可以提高性能 * * * * 数据库系统提供了四种事务隔离级别供用户选择。不同的隔离级别采用不同的锁类型来实现,在四种隔离级别中 * Serializable的隔离级别最高,Read Uncommited的隔离级别最低。大多数据库默认的隔离级别为 * Read Commited,如SqlServer,当然也有少部分数据库默认的隔离级别为Repeatable Read ,如Mysql * * (基本不用) Read Uncommited:读未提交数据(会出现脏读,不可重复读和幻读)。 * * Read Commited:读已提交数据(会出现不可重复读和幻读) * * (一般使用) Repeatable Read:可重复读(会出现幻读) * * Serializable:串行化 * * * 脏读:一个事务读取到另一事务未提交的更新新据。 * * 不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同。换句话说就是,后续读取可以读到另一事务 * 已提交的更新数据。相反,“可重复读”在同一事务中多次读取数据时,能够保证所读数据一样,也就是,后续读取 * 不能读到另一事务已提交的更新数据。 * * * 幻读:一个事务读取到另一事务已提交的insert数据。 * * * Mysql 默认的是 :Repeatable Read 可重复读(会出现幻读) * * 级别越高对于并发性能影响越大 */@Service("personServiceBean_6")@Transactionalpublic class PersonServiceBean_6 implements PersonService_6 { /** * Spring 提供的 org.springframework.jdbc.core.JdbcTemplate * 用语操作数据库 */ private JdbcTemplate jdbcTemplate; @Autowired() private DataSource dataSource; /** * 实例化personServiceBean_6 前执行的方法 * * 用于实例化JdbcTemplate 对象进行数据库操作 */ @PostConstruct public void initJdbcTemplate() { //System.out.println(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource); } public void save(Person peroson) { /** * 第一参数:sql语句 * 第二参数:通配符(?)的值 * 第三参数:通配符(?)的值的类型 * java.sql.Types中取得 */ this.jdbcTemplate.update("insert into person(name) values(?)", new Object[]{peroson.getName()}, new int[]{Types.VARCHAR}); } public void update(Person peroson) { /** * 第一参数:sql语句 * 第二参数:通配符(?)的值 * 第三参数:通配符(?)的值的类型 * java.sql.Types中取得 */ this.jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{peroson.getName(), peroson.getId()}, new int[]{Types.VARCHAR, Types.INTEGER}); } public void delete(Integer personId) { /** * 第一参数:sql语句 * 第二参数:通配符(?)的值 * 第三参数:通配符(?)的值的类型 * java.sql.Types中取得 */ this.jdbcTemplate.update("delete from person where id = ?", new Object[]{personId}, new int[]{Types.INTEGER}); } /** * 查询数据不需要事务,所有配成了propagation = Propagation.NOT_SUPPORTED * * 和readOnly = true * * 只读事务 * * @param personId * @return */ @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true) public Person getPerson(Integer personId) { /** * 第一参数:sql语句 * 第二参数:通配符(?)的值 * 第三参数:通配符(?)的值的类型 * java.sql.Types中取得 * 第四参数:RowMapper类型 * (这里需要设计一个RowMapper的子类用于返回数据) */ return (Person) this.jdbcTemplate.queryForObject("select * from person where id = ?", new Object[]{personId}, new int[]{Types.INTEGER}, new PersonRowMapper()); } @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true) public List<Person> getPersons() { /** * 第一参数:sql语句 * 第二参数:通配符(?)的值 * 第三参数:通配符(?)的值的类型 * java.sql.Types中取得 * 第四参数:RowMapper类型 * (这里需要设计一个RowMapper的子类用于返回数据) */ return (List<Person>) this.jdbcTemplate.query("select * from person", new PersonRowMapper()); }}
需要的RowMapper的子类用于返回数据,PersonRowMapper:
package com.zyy.service.impl;import com.zyy.dao.Person;import org.springframework.jdbc.core.RowMapper;import java.sql.ResultSet;import java.sql.SQLException;/** * 外部已经做过了 if(resultSet.next()) */public class PersonRowMapper implements RowMapper { public Object mapRow(ResultSet resultSet, int i) throws SQLException { Person person = new Person(resultSet.getString("name")) ; person.setId(resultSet.getInt("id")); return person; }}
配置事务很简单,只需要在类名上添加注解:@Transactional。
1.可以表示 这个bean下执行每一个方法的前都会打开失误 执行后都会关闭失误。
2.假如一个方法有多条sql语句 那么都会在一个事务内 ,不加注解则在不同的事务中执行。
3.@Transactional(noRollbackFor = Exception.class) Exception异常不回
滚 这样即使有异常也执行Sql
@Transactional(rollbackFor = Exception.class) Exception异常回滚
有Exception异常 不执行
4.事务如果有异常 不处理 都会回滚 不执行sql。
5.如果有异常,处理了,不回滚,继续执行 这两点可以利用以上的特性修改然后使其回滚。
( @Transactional(rollbackFor = Exception.class) )
接下来,介绍一下 事务的传播属性:
REQUIRED(80%使用率):业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中
那么加入到该事务,否则为自己创建一个新的事务。
NOT_SUPPORTED(查询操作可以加):声明方法不需要事务。如果方法没有关联到一个事务,容器不会为
它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方
法调用结束后,原先的事务便会恢复执行。
REQUIRESNEW:属性表明不管是否存在事务,业务方法总会为自己发起一个新的事务。
如果方法已经运行在一个事务中,则原有事务会被挂起,新的事务会被
创建,直到方法执行结束,新事务才算结束,原先的事务才会恢复执行。
MANDATORY:该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起
自己的事务。如果业务方法在没有事务的环境下调用,容器就会抛出例外。
SUPPORTS:这一事务属性表明,如果业务方法在某个事务范围内被调用,则方法成为该事
务的一部分。如果业务方法在事务范围外被调用,则方法在没有事务的环境下
执行。
Never:指定业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,容器会
抛出例外,只有业务方法没有关联到任何事务,才能正常执行。
NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按
REQUIRED属性执行.它使用了一个单独的事务,这个事务拥有多个可以回滚的保存
点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager
事务管理器起效
然后在了解一下,数据库系统提供了四种事务隔离级:
数据库系统提供了四种事务隔离级别供用户选择。不同的隔离级别采用不同的锁类型来实现
在四种隔离级别中,Serializable的隔离级别最高,Read Uncommited的隔离级别最
低。大多数据库默认的隔离级别为Read Commited,如SqlServer,当然也有少部分数
据库默认的隔离级别为Repeatable Read ,如Mysql
ReadUncommited:读未提交数据(会出现脏读,不可重复读和幻读)。
ReadCommited:读已提交数据(会出现不可重复读和幻读)
RepeatableRead:可重复读(会出现幻读)
Serializable:串行化
脏读:一个事务读取到另一事务未提交的更新新据。
不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同。换句话说就是,后续读取
可以读到另一事务已提交的更新数据。相反,“可重复读”在同一事务中多次读取数
据时,能够保证所读数据一样,也就是,后续读取不能读到另一事务已提交的更新数
据。
幻读:一个事务读取到另一事务已提交的insert数据。
junit4.4测试代码:
package test.junit.test;import com.zyy.dao.Person;import com.zyy.service.PersonService_6;import org.junit.After;import org.junit.Before;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * SpringJDBCTest Tester. * * @author <Authors name> * @version 1.0 */public class SpringJDBCTestTest { private PersonService_6 personService_6 ; @Before public void before() throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans_4.xml"); this.personService_6 = (PersonService_6)applicationContext.getBean("personServiceBean_6"); } @After public void after() throws Exception { } @Test public void save() { personService_6.save(new Person("CaMnter")); } @Test public void update() { Person person = new Person("CaMnter_update") ; person.setId(2); personService_6.update(person); } @Test public void delete() { personService_6.delete(3); } @Test public void getPerson() { Person person = personService_6.getPerson(new Integer(2)) ; System.out.println("id:"+person.getId()+" name:"+person.getName()); } @Test public void getPersons() { for (Person person : this.personService_6.getPersons()) { System.out.println("id:"+person.getId()+" name:"+person.getName()); } }}
那么,就来测试getPerson和getPersons吧:
- 8.Spring + JDBC + 事务(注解)
- 【Spring】在Spring框架下使用注解配置JDBC事务
- 使用注解方式配置spring中的jdbc事务
- Spring JDBC-使用注解配置声明式事务
- Spring整合JDBC、Spring的AOP事务开发、Spring注解整理
- Spring事务之一(JDBC简介)
- spring配置JDBC事务
- spring(JDBC)事务配置
- spring事务注解
- spring事务注解
- spring 事务注解
- Spring 事务注解
- Spring 注解事务说明
- Spring+Hibernate注解事务
- spring 注解事务
- spring事务注解
- spring添加注解事务
- spring注解事务
- Linux之参考资料
- 关于JSP中的i++和++i和i+1和getParameterValues类型转换和for中的遍历问题
- 学ios需要了解的C语言基础知识-5-函数
- Gradle修改本地仓库的位置
- unity插件开发之对齐小工具
- 8.Spring + JDBC + 事务(注解)
- Oracle审计功能
- 搭建最小MySQL环境
- 浅析oracle数据文件scn
- c语言单链表操作
- Sublime Text2.0.2注册码
- 使用Git制作和管理Patch
- 哈希表
- Ubuntu打包压缩命令总结