一、JDBC
早期SUN公司想编写一套可以连接天下所有数据库的API,但是当他们刚刚开始时就发现这是不可完成的任务,因为各个厂商的数据库服务器差异太大了。后来SUN开始与数据库厂商们讨论,最终得出的结论是,由SUN提供一套访问数据库的规范(就是一组接口),并提供连接数据库的协议标准,然后各个数据库厂商会遵循SUN的规范提供一套访问自己公司的数据库服务器的API出现。SUN提供的规范命名为JDBC,而各个厂商提供的,遵循了JDBC规范的,可以访问自己数据库的API被称之为驱动。
数据库连接池:C3P0、DBCP—%20Apache%20CommonPool、Druid、Hikari
二、ORM
Hibernate
Hibernate%20是一个开源的对象关系映射框架,它对JDBC%20进行了非常轻量级的对象封装,它将%20POJO%20与数据库表建立映射关系,是一个全自动的%20orm%20框架,hibernate%20可以自动生成%20SQL%20语句,自动执行,使得%20Java%20程序员可以使用面向对象的思维来操纵数据库。Hibernate%20需要定义实体类和%20hbm%20映射关系文件(IDE%20一般有工具生成)。Hibernate%20可以使用%20HQL、Criteria、Native%20SQL三种方式操作数据库。也可以作为%20JPA%20适配实现,使用%20JPA%20接口操作。
Mybatis
MyBatis%20是一款优秀的持久层框架,它支持定制化%20SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC%20代码和手动设置参数以及获取结果集。Mybatis%20可以使用简单的XML或注解来配置和映射原生信息,将接口和%20Java的POJOs(Plain%20Old%20Java%20Objects,普通的Java对象)映射成数据库中的记录
Mybatis与Hibernate的区别?
Hibernate是全自动,Mybatis是半自动。Mybatis
- 优点:原生SQL(XML语法),直观,容易优化
- 缺点:繁琐,可以用Mybatis-generator、Mybatis-Plus之类的插件弥补
Hibernate
- 优点:简单场景不用写SQL(HQL、Cretiria、SQL)
- 缺点:不好优化sql,对DBA不友好
Spring管理事务
先看看JDBC如何操作事务?
再看看Spring是如何无侵入的进行事务管理的?public%20void%20updatePrice()%20throws%20SQLException%20{%20%20try%20{%20%20%20%20%20%20Connection%20conn%20=%20getConnection();%20%20%20%20%20%20//关闭自动提交%20%20%20%20%20%20conn.setAutoCommit(false);%20%20%20%20%20%20String%20sql%20=%20"update%20goods%20set%20price%20=?%20where%20id=?%20";%20%20%20%20%20%20PreparedStatement%20ptmt%20=%20conn.prepareStatement(sql);%20%20%20%20%20%20%20ptmt.setDouble(1,%203500);%20%20%20%20%20%20ptmt.setString(2,%20"1");%20%20%20%20%20%20//执行%20%20%20%20%20%20ptmt.execute();%20%20%20%20%20%20//提交事务%20%20%20%20%20%20conn.commit();%20%20}%20catch%20(Exception%20e)%20{%20%20%20%20%20%20//回滚事务%20%20%20%20%20%20conn.rollback();%20%20%20%20%20%20e.printStackTrace();%20%20}}
实现原理:事务管理器+AOP
源码分析Spring事务实现过程
示例代码:在goodsService.updatePrice方法上加了事务注解。@RequestMapping("/updateprice")public String updateprice(Double price,Integer age){goodsService.updatePrice(1,price);int i=10/0;userService.updateAge(1,age);return "sucess";}
- 请求进入Controller,调用
goodsService的时候,调用的实际上是goodsService的代理对象

- 到代理类的方法中
org.springframework.aop.framework.ReflectiveMethodInvocation#proceed - 进入事务拦截器的方法
里面有个TransactionInterceptor
TransactionInterceptor方法里面进行了事务管理protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable {// If the transaction attribute is null, the method is non-transactional.TransactionAttributeSource tas = getTransactionAttributeSource();final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);final PlatformTransactionManager tm = determineTransactionManager(txAttr);final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {// Standard transaction demarcation with getTransaction and commit/rollback calls.TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);Object retVal = null;try {// This is an around advice: Invoke the next interceptor in the chain.// This will normally result in a target object being invoked.//执行目标方法retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {//回滚exceptioncompleteTransactionAfterThrowing(txInfo, ex);throw ex;}finally {cleanupTransactionInfo(txInfo);}//提交事务commitTransactionAfterReturning(txInfo);return retVal;}...
上述是简单场景的事务处理,如果是多个
service方法,并且都加了@Transactional注解,那事务怎么算呢?那就需要学习Spring里的事务传播了。 ```java public Class ServiceA{@Transactional void methodA(){
//....
} }
public Class ServiceB{
@Transactionalvoid methodB(){//....}
七种事务的传播行为:
PROPAGATION_REQUIRED(默认) 表示当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。PROPAGATION_SUPPORTS表示当前方法不必须在一个具有事务的上下文中运行,如:ServiceA.methodA()调用ServiceB.methodB(),如果methodA方法上有事务,那么methodB加入他的事务,如果methodA上没有事务,那么methodB也不开事务PROPAGATION_MANDATORY必须被开启事务的方法调用,否则报错PROPAGATION_REQUIRES_NEW强制自己开启一个新的事务,如果一个事务已经存在,那么将这个事务挂起.如ServiceA.methodA()调用ServiceB.methodB(),methodB()上的传播级别是PROPAGATION_REQUIRES_NEW的话,那么如果methodA报错,不影响methodB的事务,如果methodB报错,那么methodA是可以选择是回滚或者提交的,就看是否将methodB报的错误抛出还是try catch了.PROPAGATION_NOT_SUPPORTED总是非事务的执行,并且挂起任何事务.就是如果methodA方法执行到methodB这里了,methodA的事务就被挂起,然后methodB非事务的执行,然后等methodB方法运行结束,methodA的事务再继续.这个的好处就是methodB报错了不会让methodA回滚.PROPAGATION_NEVER总是非事务地执行,如果存在一个活动事务,则抛出异常PROPAGATION_NESTED表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则同propagation.required的一样事务失效的几个原因:
- Spring的事务注解
@Transactional只能放在public修饰的方法上才起作用,如果放在其他非public(private,protected)方法上,虽然不报错,但是事务不起作用 - 如果采用Spring+SpringMVC,则
context:component-scan重复扫描问题可能会引起事务失败。如果spring和mvc的配置文件中都扫描了service层,那么事务就会失效。原因:因为按照Spring配置文件的加载顺序来讲,先加载SpringMVC配置文件,再加载Spring配置文件,事物一般都在srping配置文件中进行配置,如果此时在加载srpingMVC配置文件的时候,把service也给注册了,但是此时事物还没加载,也就导致后面的事物无法成功注入到service中。所以把对service的扫描放在Spring配置文件中或是其他配置文件中。 - 如使用mysql且引擎是MyISAM,则事务会不起作用,原因是MyISAM不支持事务,可以改成InnoDB引擎
@Transactional注解开启配置,必须放到listener里加载,如果放到DispatcherServlet的配置里,事务也是不起作用的。- Spring团队建议在具体的类(或类的方法)上使用
@Transactional注解,而不要使用在类所要实现的任何接口上。在接口上使用@Transactional注解,只能当设置了基于接口的代理时它才生效。因为注解是不能继承 的,这就意味着如果正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装。 - 在业务代码中如果抛出
RuntimeException异常,事务回滚;但是抛出Exception,事务不回滚;默认对RuntimeException回滚 - 如果在加有事务的方法内,使用了try…catch..语句块对异常进行了捕获,而catch语句块没有
throw new RuntimeExecption异常,事务也不会回滚 - 在类A里面有方法a 和方法b, 然后方法b上面用
@Transactional加了方法级别的事务,在方法a里面 调用了方法b,方法b里面的事务不会生效。原因是在同一个类之中,方法互相调用,切面无效,而不仅仅是事务。这里事务之所以无效,是因为Spring的事务是通过aop实现的。
代码示例:
可以看出这个this,并不是代理对象,事务也就不能生效了。
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论