Spring的数据库操作和事务管理
来源:互联网 发布:base 私有密码算法 编辑:程序博客网 时间:2024/06/06 01:14
一.概述
spring的数据库操作:spring是一个优秀的一站式框架,其中涵盖了很多持久化框架模板对象,如JDBC,hibernate,mybatis对象模板,极大地简化了数据库操作。
事务:表示逻辑上的一组操作,这组操作要么一起成功要么一起失败。最经典的就是银行转账业务,假设甲转一百块给乙,在转账过程中,可能发生各种异常,若此时没有事务,可能会发生甲的钱少了,而乙的钱没有增加的事件。
二.动态代理手写一个AOP的事务管理器(spring管理事务的机制)
假设现在在项目中不引入spring框架,我们来自己手写一个面向切面的事务管理机制。事务管理应该放在service,dao层只负责数据库的增删改查,假设我们现在有一系列service代码(如UserService,CustomerService,MoneyService),要是在每一个service单独实现事务管理,显然过于复杂,不符合编程中代码复用的思想。那么我们可以把这些重复的事务管理操作抽取到一个工厂类中,工厂负责生产Service,并根据是否有注解,区分这个Service是否要进行事务处理。我们可以用动态代理技术对Service进行代理,对需要进行事务处理的Service的方法进行增强。最终实现Service层的事务自动管理。
public <T extends Service> T getService(Class<T> clazz){//把泛型限制在Service的子类中try{//--把所有Service都写在配置文件中,根据配置文件创建具体的ServiceString infName = clazz.getSimpleName();String implName = prop.getProperty(infName);final T service = (T) Class.forName(implName).newInstance();//动态代理生成代理后的Service,实现事务管理自动化//--为了实现AOP,生成service代理,根据注解确定在Service方法执行之前和之后做一些操作,比如:事务管理/记录日志/细粒度权限控制....T proxyService = (T) Proxy.newProxyInstance(service.getClass().getClassLoader(), service.getClass().getInterfaces() , new InvocationHandler(){//根据注解控制事务public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {if(method.isAnnotationPresent(Tran.class)){//如果有注解,则管理事务:try{TransactionManager.startTran();//--自定义事务管理器,开启事务Object obj = method.invoke(service, args);//--真正执行方法TransactionManager.commit();//--提交事务return obj;}catch (InvocationTargetException e) {TransactionManager.rollback();//--回滚事务throw new RuntimeException(e.getTargetException());} catch (Exception e) {TransactionManager.rollback();//--回滚事务throw new RuntimeException(e);}finally{TransactionManager.release();//--释放资源}}else{//如果没有注解,则不管理事务,直接执行方法return method.invoke(service, args);}} }); return proxyService;}catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}}三.spring中的事务操作解析
spring提供了很多主流的持久化框架模板,包括最基础的JDBC,ORM框架hibernate,mybatis等。具体模板类对应如下:
下面以JDBC模板为例,解析spring持久化模板类的使用。
1.导入必要的jar包
以mysql为例,故要导入mysql驱动包
spring中jdbc操作相关包
spring事务操作相关包
2.编写测试类:spring持久化模板使用非常简单,获得模板对象后直接就可以对数据库进行增删改查
@Test// JDBC 模板的基本使用:public void demo1(){//注册数据库配置DriverManagerDataSource dataSource = new DriverManagerDataSource();dataSource.setDriverClassName("com.mysql.jdbc.Driver");dataSource.setUrl("jdbc:mysql:///spring_crc");dataSource.setUsername("root");dataSource.setPassword("123");//获得模板类后就可以直接操作数据库JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);jdbcTemplate.update("insert into account values (null,?,?)", " crc",10000d);}
3.每一次使用都要配置数据库显然过于麻烦,故把数据库的配置交给spring管理,在主配置文件中配置如下bean,并使用c3p0代替原来的数据源<bean id="dataSource"class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///spring_crc"/> <property name="username" value="root"/> <property name="password" value="123"/> </bean>
4.还可以把模板类对象交给spring管理,由spring创建模板类对象<! -- 配置 JDBC 模板 对象--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean>
5.此时JDBC模板的操作可以简化成如下形式
@RunWith(SpringJUnit4ClassRunner. class)@ContextConfiguration("classpath:applicationContext.xml")public class SpringDemo3 {@Resource(name="jdbcTemplate")private JdbcTemplate jdbcTemplate;@Test// 插入操作public void demo1(){jdbcTemplate.update("insert into account values (null,?,?)", " crc",10000d);}@Test// 修改操作public void demo2(){jdbcTemplate.update("update account set name=?,money =? where id = ?", "hello",10000d,5);}@Test// 删除操作public void demo3(){jdbcTemplate.update("delete from account where id = ?", 5);}@Test// 查询一条记录public void demo4(){Account account = jdbcTemplate.queryForObject("select * from account whereid = ?", new MyRowMapper(), 1);System. out.println(account);}
小结:至此,JDBC的简单使用全部完毕,我们可以把数据库配置和模板对象创建交给spring管理,最后只需要
调用简单的API就可以完成增删改查工作。
四.spring中的事务管理(主要解析声明式事务)
1.事务的基本说明
事务的四个特性
原子性 :强调事务的不可分割.
一致性 :事务的执行的前后数据的完整性保持一致.
隔离性 :一个事务执行的过程中,不应该受到其他事务的干扰
持久性 :事务一旦结束,数据就持久到数据库
事务的安全性问题
脏读 :一个事务读到了另一个事务的未提交的数据
不可重复读 :一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致.
虚幻读 :一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致.
事务的隔离级别
未提交读 :脏读,不可重复读,虚读都有可能发生
已提交读 :避免脏读。但是不可重复读和虚读有可能发生
可重复读 :避免脏读和不可重复读.但是虚读有可能发生.
串行化的 :避免以上所有读问题.
其中,
Mysql 默认:可重复读
Oracle 默认:读已提交
2.spring管理事务的对象
org.springframework.jdbc.datasource.DataSourceTransactionManager使用SpringJDBC 或iBatis进行持久
化数据时使用
org.springframework.orm.hibernate3.HibernateTransactionManager使用Hibernate版本进行持久化数据时使用
3.spring中可以定制的事务信息
*隔离级别
* 传播行为
* 超时信息
* 是否只读
其中事务的传播行为分为以下几种
*保证同一个事务中
PROPAGATION_REQUIRED支持当前事务,如果不存在 就新建一个(默认)
PROPAGATION_SUPPORTS支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY支持当前事务,如果不存在,抛出异常
* 保证没有在同一个事务中
PROPAGATION_REQUIRES_NEW如果有事务存在,挂起当前事务,创建一个新的事务
PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER以非事务方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED如果当前事务存在,则嵌套事务执行
4.spring中管理事务的两种方式
spring中管理方式的方式可分为两种:编程式和声明式事务。由于编程式事务使用较少(不符合spring习惯),故接下来重点阐述
声明式事务,声明式事务又可以分为XML配置方式和注解配置方式。在配置之前首先应该明确,spring中管理事务对象的依赖关系
如图:
现在以配置JDBC的事务管理为例,分别演示用XML方式和注解方式配置声明式事务。如下:
XML方式
步骤1.导入AOP开发相关的包,因为XML方式配置就是基于AOP开发思想的
aop联盟.jar;Spring-aop.jar; aspectJ.jar;spring-aspects.jar
步骤2.配置事务管理器,注意上图,JDBC事务管理器依赖于DataSource存在,故在配置中需要体现此种关系
<bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
步骤3.配置事务的通知<! -- 配置事务的增强 --><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes> <! --方法中可以配置的几个属性isolation="DEFAULT" 隔离级别propagation="REQUIRED" 传播行为read-only="false" 只读timeout="-1" 过期时间rollback-for="" -Exceptionno-rollback-for="" +Exception--><!-- 配置需要事务管理的方法,以转账方法为例--> <tx:method name="transfer" propagation="REQUIRED"/> </tx:attributes></tx:advice>
步骤4.配置将通知织入目标
<aop:config><!--表示把事务织入到AccountServiceIml类中,所有以tranfer开头的方法中--> <aop:pointcut expression="execution(*com.cai.transaction.AccountServiceImpl.transfer(..))" id="pointcut1"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/> </aop:config>
注解方式
步骤1,导包和开启事务管理与XML方式一致,不再累述。
步骤2.开启注解管理事务
<! -- 开启注解事务管理 --><tx:annotation-driven transaction-manager="transactionManager"/>
步骤3.在使用的类中添加一个注解@Transactional
小结:对比以上两种方式,可以得出一个结论,XML方式配置比较麻烦,但是比较统一,可以一次性解决问题。注解配置方式比较简单,
且比较灵活,可以在比较少事务管理的时候使用注解方式。在对项目要求严谨时,使用XML方式。
五.总结
本博客一开始先使用动态代理技术手写了一个AOP的事务管理对象,让人大致明白了spring内部是
怎么进行事务管理的。然后简单介绍了spring中数据库操作的模板类及其API,最后使用两种方式
配置事务管理操作。通过这样一套流程,就可以使用spring进行完整的数据库操作了。
- Spring的数据库操作和事务管理
- Spring的事务管理和数据库事务相关知识
- 【j2ee spring】7、spring与数据库的连接的操作事务管理
- 使用c3p0连接数据库、操作数据库和数据库的事务管理,基于mybatis框架
- Spring 数据库事务管理
- spring 数据库事务管理
- 深入Spring数据库事务管理
- Spring的编程式事务管理和声明式事务管理
- 关于事务管理的理解和Spring事务管理详解
- Spring的AOP和事务管理机制概览
- Spring的AOP和事务管理机制概览
- Spring的AOP和事务管理机制概览
- Spring的AOP和事务管理机制概览
- Spring集成的jdbc编码和事务管理
- spring事务管理的注解和配置
- Spring集成的JDBC编码和事务管理
- JdbcDaoSuppert和spring的事务管理--第五天
- Spring框架的JDBC模板和事务管理
- 使用mondorescue将本机linux centos 7服务器制作成光盘
- kotlin学习笔记——扩展函数(anko)和网络请求
- 扩展二进制数
- HDU1196
- 使用Visual Studio Code开发Arduino
- Spring的数据库操作和事务管理
- 设计接口
- [RK3288][Android6.0] 调试笔记 --- Camera丢帧检测
- Android打开相机和相册的方法--很受用
- linux设备驱动读书笔记
- 详解manacher算法,及其扩展
- 虚拟机与主机的文件共享
- shiro:realm域实例2
- SSM框架Spring+SpringMVC+MyBatis——详细整合教程