`
wuhuajun
  • 浏览: 93897 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

SPRING对DAO层的统一封装

 
阅读更多

1. 异常:spring对dao层进行了统一的封装 首先解决各个持久层jdbc,hibernate,jdo,ibatis等的异常处理的问题。

所以spring提供了一套和技术实现无关的,面向DAO的运行时异常体系,并通过异常转换器转换为spring的异常。

针对jdbc的异常SQLException 抛出的错误码和错误状态 SQLExceptionTranslator|SQLErrorcodeSQLExceptionTranslator |SQLStateSQLExceptionTranslator 进行转换

其他持久层框架 类同。

 

2.JdbcTemplate,TransactionTemplate,通过模版加回调的方式进行封装 将整个jdbc操作中固定不变的和可变的进行分开将固定不变的放到JdbcTemplate中可变的通过回调的方式开放给程序员调用,也可以继承JdbcDaoSupport。并保证JdbcTemplate线程安全性(Dao都是一份代码共享JdbcTemplate的)。spring为各个持久层提供了模版类 封装异常相关信息。

TransactionTemplate和JdbcTemplate一样使用模版加回调的方式实现 但是这个是控制事务的一般加载service层上面的,统一能保证线程安全。内部实现是spring事务管理封装来实现的参考3事务管理。

(先说下原理 内部使用的都是ThreadLocal中存放的connection,所以在service层TransactionTemplate开启的事务使用的连接和JdbcTemplate使用的都是同一个数据库连接,在事务管理细说)。

 

3.事务管理:

============================补充start=======================

事务隔离级别 一般应用事务隔离级别都是Read Commited,这个级别能解决很多数据库的并发问题 比如脏读,撤销事务时候把已提交的事务数据覆盖,但是

  如果两个事务同事执行都需要修改金额字段  a事务读取金额100元  在a读取完还没有执行操作 b事务读取100并修改为90  a事务这个时候再加10 原本以为是110的但是现在还是100

  Read Commited不能解决这个问题 这个时候要么查询出来使用select ...forupdate(不利于并发)  要么在执行增加的sql语句同时进行查询合入一个sql语句,防止其他事务参入,主要因为读取时候并没有把数据锁定。

  

spring如何实现上面说的线程安全性以及事务管理

  在web开发中一般每个请求对应一个线程,每个请求一般都会经历controller->service->dao =>返回 其中涉及到一个有状态的对象connection。  这个时候你需要保证线程安全 要么涉及到的bean都是无状态的,或者都创建多例(耗内存不考虑,springmvc controller默认实现都是单例的)。 还有种办法就是采用锁机制保证并发,但是connection参数在方法之间的传递又存在问题了。

对比之下Theadlocal是最好的选择能保证线程安全又能方便参数的传递。

一个请求中:

如果service层有事务 在每个事务开启时候获取到connection放到Threadlocal 在dao操作时候通过Threadlocal 获取到这个相同的connection,事务结束释放connection连接

(注意只在事务期间占用连接的,connection  很宝贵的。即使你下面代码又开启事务还得重新获取)。

如果service层没事务 在dao操作时候获取连接放到Threadlocal中去执行完成释放connection连接。

如果是多数据源事务也一样在service层通过事务管理器开启事务就决定了使用那个数据源的连接,所以dao也使用这个连接。(数据源是注入到事务管理器里面的比如DataSourceTransactionManager)

spring这样实现了事务的功能 又保证了连接的线程安全,可以参考spring TransactionSynchronizationManager定义的很多ThreadLocal都是为了维护无状态bean用的。

============================补充end =======================

 

3.1

spring事务管理功能的实现主要三个类:

PlatformTransactionManager    持久层jdbc,hibernate,jdo,jta事务管理器的抽象 spring为各个不同持久层体提供不同的实现 这个只有三个方法开启事务 提交事务 回滚事务 都是针对connection 直接通过ThreadLocal获取不就行了为什么要各自有自己的实现呢?比如hibernate session 开启事务不光 setAutoConnection(false)那么简单 做了好多自己的事情在里面。提交回滚也一样。 涉及到缓存之类的东西。

TransactionDefinition                对应在xml文件中对事务的配置属性 比如事务隔离级别,超时时间,只读状态啊 传播特性之类的

TransactionStatus                    当前事务的运行状态 比如事务回滚 事务savepoint。。。

 

3.2

事务的7种传播特性:一般应用程序不建议service层调用service层的方法,但是如果调用了就可能存在嵌套事务的可能,如果各个service层方法定义了自己的事务,那么在调用过程中事务之间如何相互配合呢?

                                1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务。如果没有事务则开启

                                2. PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行

                                3. PROPAGATION_MANDATORY: 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。

                                4. PROPAGATION_REQUIRES_NEW: 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。

                                5. PROPAGATION_NOT_SUPPORTED: 总是非事务地执行,并挂起任何存在的事务。

                                6. PROPAGATION_NEVER: 总是非事务地执行,如果存在一个活动事务,则抛出异常

                                7. PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。

1,2,3,6很容易理解就是字面的意思 7是个jdbc3.0里面支持的savepoint的概念,能回滚到保存点上。4,5里面都有个事务挂起的操作到底什么是事务的挂起呢?

PROPAGATION_REQUIRES_NEW :首先挂起当前事务 挂起的意义是将所有的资源进行保存,以便进行恢复,挂起后开启一个新事务 在新事务中允许,新事务运行结束 老事务恢复继续允许 新老事务互不干涉。

PROPAGATION_NESTED:开启一个嵌套的事务,是一个已经存在事务的子事务,嵌套事务执行会获取保存点savepoint如果失败conn.roolback(savepoint)回滚。 嵌套事务是外部事务的一部分, 只有外部事务结束后它才会被提交.  

总结:PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 嵌套事务也会被 commit, 这个规则同样适用于 roll back. 外部事务能决定嵌套事务的提交回滚。而内部事务如果执行失败能回滚到指定的点上去。

 

3.3

声明式事务三种配置方式:

A:TransactionProxyFactoryBean方式(侵入式)

 

        <bean id="txManager"

class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource" />

</bean>

<bean id="bbtForumTarget" 

     class="com.test.service.impl.BbtForumImpl"

     p:forumDao-ref="forumDao"

     p:topicDao-ref="topicDao"

     p:postDao-ref="postDao"/>

 

<bean id="bbtForum"

class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"(类似aop ProxyFactoryBean)

p:transactionManager-ref="txManager"(类似aop 增强)

p:target-ref="bbtForumTarget"(类似aop 目标对象)>

<property name="transactionAttributes">

<props>

<prop key="addTopic">

PROPAGATION_REQUIRED,+PessimisticLockingFailureException

                </prop>

<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>

<prop key="*">PROPAGATION_REQUIRED,-tion</prop>

</props>

</property>

</bean>

 

B:tx/aop Schema方式(非侵入式)

       <bean id="bbtForum"

class="com.test.service.impl.BbtForumImpl"

p:forumDao-ref="forumDao"

p:topicDao-ref="topicDao"

p:postDao-ref="postDao"/>

 

 

<bean id="transactionManager"

class="org.springframework.jdbc.datasource.DataSourceTransactionManager"

p:dataSource-ref="dataSource"/>

 

<aop:config>

<aop:pointcut id="serviceMethod"

expression="execution(* com.test.service.*Forum.*(..))" />

<aop:advisor pointcut-ref="serviceMethod"

advice-ref="txAdvice" />

</aop:config>

<tx:advice id="txAdvice" transactionManager=“transactionManager”>

        <tx:attributes> 

            <tx:method name="get*" read-only="false"/>

            <tx:method name="add*" rollback-for="PessimisticLockingFailureException"/>

            <tx:method name="update*"/>         

        </tx:attributes>

    </tx:advice>

C:注解方式

       <bean id="txManager"

class="org.springframework.jdbc.datasource.DataSourceTransactionManager"

p:dataSource-ref="dataSource"/>

        <!--事务注解扫描器-->          

<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />

        在需要加入事务的类上面加入@Transactional注解就可以了

 

和spring aop实现对比模拟实现,<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />可以在后处理bean里面完成代理对象的生成。

类似实现:

织入切面 

@Aspect //1,开启事务提交事务

public class Transaction{

   @Around("@annotation(XXXXXXXXXXX.Transactional)")

   public void transaction(ProcessdingJoinPoint pjp){

          PlatformTransactionManager tx = null;//获取配置到<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />里面的事务管理器txManager

          tx.getTransaction();

          pjp.proceed();

          tx.commit();
   }

}

 

@Aspect //2,回滚事务

public class ThrowsTransaction{

   @AfterThrowing(value="@annotation(value="XXXXXXXXXXX.Transactional",throwing="iae"))

   public void ThrowsTransaction(Exception iae){

          PlatformTransactionManager tx = null;//获取配置到<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />里面的事务管理器txManager

        tx.rollback();

   }

}

 

最后加上注解扫描 <aop:aspectj-autoproxy />

 

区分下: <aop:aspectj-autoproxy />这个是aop注解切面的扫描 扫描标注@Aspect切面 生成代理。

                   <tx:annotation-driven/>这个是事务注解扫描 专门为事务注解提供的扫描@Transactional会被扫描到至于切面实现类上面的实现spring已经实现隐藏起来了。

 

 

如果在service层需要保存一个大文件 保存完成后需要修改数据库几个字段的值,这个时候就需要在service层做个异步处理 就是启动一个新线程来保存文件 保存后修改数据库几个字段这个时候的事务又是什么样的呢?

分析:

启动一个新的线程调用service层的方法来修改数据库,如果这个方法需要事务支持那么首先会从threadlocal中获取到connection连接 如果没有(肯定是没有的因为是新启动的线程)

就去连接池中获取开启事务并绑定。执行到dao操作修改数据库字段再从当前线程的threadlocal获取到数据库连接  完成后事务提交释放连接,整个过程中和开启线程的service方法事务没有任何的关系 ,他们的事务都是相互独立运行的没有任何关系。

所以不用担心多线程下会导致事务失效的问题,只是在多线程下 传播特性不能传播到开启的线程上面去的而已。

 

 

spring把connection连接都管理好了 我们一般不需要自己获取到连接 如果项目中一定要用怎么弄呢?

肯定要从线程的threadlocal中获取不然就达不到spring事务控制的效果了,如何获取呢,spring提供了DataSourceUtils类能让你很方便的获取到线程threadlocal绑定的数据库连接。

 

 

DataSourceUtils获取到的连接是否需要进行是否呢?

分情况:

如果是有事务的那么就不要释放了 因为如果你释放了 spring怎么拿这个连接去提交事务呢。

如果是没有事务那么就一定要是否的 不让会导致 连接泄漏的问题。

无论是释放还是获取都使用DataSourceUtils提供的方法。

其他持久层 都有类似的Util。

 

 

3
3
分享到:
评论

相关推荐

    ifunsu封装基于springjdbc的dao层

    ifunsu封装基于springjdbc的dao层,具体用法请看本站博客http://blog.csdn.net/ifunsu 。

    Spring对DAO的支持.doc

    本文将从三个方面探讨Spring对DAO的支持:传统模式的DAO,Spring对JDBC的DAO支持,以及Spring对Hibernate的DAO支持。 ### 1. 传统DAO模式 在传统的DAO模式中,通常需要实现以下几个组件: - **DAO工厂**:创建DAO...

    ifunsu封装基于springjdbc的dao层api

    标题"ifunsu封装基于springjdbc的dao层api"指的是一个特定的项目或库,名为ifunsu,它已经对Spring JDBC进行了封装,以创建更易用的数据访问对象(DAO)层API。DAO层是应用程序中负责与数据库进行交互的部分,通常...

    spring的持久层封装

    标题:“spring的持久层封装” 描述:“spring持久层封装,新手可用,物超所值” 标签:“spring” 根据给定的文件信息,我们将深入探讨Spring框架中持久层封装的概念、重要性和具体实现方式。 ### 一、Spring...

    mongoTemplate工具类Dao层方法封装.zip

    这个资源包“mongoTemplate工具类Dao层方法封装.zip”显然提供了两种版本的MongoTemplate操作集合的代码示例,旨在帮助开发者更高效地进行数据访问层(Dao层)的开发。以下是关于MongoTemplate及它在 Dao 层中使用的...

    Spring3 JDBC 通用DAO封装2 dao层终于完成dao层大概上传完整代码

    本篇将围绕“Spring3 JDBC通用DAO封装”这一主题展开,介绍如何实现一个高效的DAO层,并分享相关代码示例。 1. **Spring3 JDBC概述** Spring3 JDBC通过提供JdbcTemplate和SimpleJdbcInsert等工具类,帮助开发者...

    基于Annotation并对DAO层封装具有分页功能的S2SH整合实例

    在这个基于Annotation并对DAO层封装具有分页功能的S2SH整合实例中,我们将探讨如何利用这些技术的特性来提高开发效率和代码可维护性。 首先,让我们深入了解一下Struts2。Struts2是基于MVC模式的开源Web应用框架,...

    mongoDB DAO层封装

    在这个项目中,我们主要基于MongoDB 3.0版本和Spring Data 1.5进行整合,实现了DAO层的封装。下面将详细解释这些关键知识点。 1. MongoDB MongoDB是一个流行的开源文档型数据库,它采用了NoSQL的数据模型,以JSON...

    使用Spring实现DAO模式

    使用Spring实现DAO模式 在软件开发领域,设计模式是一种被广泛接受的解决特定问题的方案。其中,DAO(Data Access Object)模式旨在提供一种抽象的数据访问机制,将数据访问的逻辑封装在一个对象中,从而使得应用...

    Mybatis通用DAO设计封装(mybatis)

    使用Spring框架进行依赖注入,将DAO实例注入到Service层,实现解耦合。同时,Spring的AOP(面向切面编程)可以方便地实现日志记录、性能监控等功能。 9. **性能优化**: 考虑缓存策略,如一级缓存(SqlSession...

    dao.rar_spring-dao

    DAO(Data Access Object)模式是Java开发中常用的一种设计模式,用于封装对数据库的操作,使得业务逻辑层与数据访问层解耦。Spring框架提供了对DAO的支持,通过依赖注入(DI)和面向切面编程(AOP)简化了数据访问...

    Spring的作用贯穿了整个中间层,将Web层、Service层、DAO层及PO无缝整合

    2. **分层设计**:Spring框架支持分层的设计模式,这意味着不同的业务功能可以被封装在不同的层中,例如Web层负责处理用户界面,Service层处理业务逻辑,DAO层处理数据访问。这样的设计有助于保持代码的清晰度,并...

    Hibernate封装dao层

    对DAO层进行充分的单元测试,验证其功能的正确性,可以使用JUnit和Mockito等工具。 9. **最佳实践**: - 避免在DAO层进行复杂的业务逻辑,保持DAO层的简洁性。 - 使用连接池管理数据库连接,如C3P0、HikariCP等...

    使用配置文件对DAO层封装具有分页功能的S2SH整合实例_好资源0分送

    - **泛型支持**: 由于Spring对泛型的支持有限,因此在DAO层封装时采用了泛型加抽象类的方式。具体来说,可以通过定义一个抽象类`BaseDaoSupport`来实现泛型支持,该抽象类包含了一些通用的方法和属性。 ```java ...

    spring 对dao 的操作

    标题提到的"spring 对dao 的操作",指的是Spring如何协助我们实现数据访问对象(DAO)层的编程。在这个基于SSH(Spring、Struts、Hibernate)的项目中,DAO层是连接业务逻辑与数据库的关键部分。 首先,我们需要...

    Spring的DAO

    Spring的DAO支持是其核心模块之一,用于简化数据访问层(DAO)的开发,通过将固定的数据访问逻辑和业务逻辑分离,提高了代码的可维护性和复用性。Spring的DAO设计模式主要体现在模板(Template)和回调(Callback)...

    Spring支持DAO需要的jar包

    1. **Spring JDBC支持**:Spring通过JDBC抽象层提供了模板类JdbcTemplate和NamedParameterJdbcTemplate,它们封装了常见的JDBC操作,如执行SQL查询、更新、事务管理等,大大减少了手动处理结果集和异常的工作。...

    经典泛型dao层代码,非常好用简易

    然后,利用Spring的依赖注入(DI)特性,可以在Service层或其他组件中轻松注入泛型DAO的实例,从而实现对数据库的操作。 #### 结论 泛型DAO层为SSH框架下的数据访问提供了统一、高效且灵活的解决方案。通过上述...

    spring几种Dao支持配置

    在Spring框架中,DAO(Data Access Object)层是应用程序与数据库交互的核心部分。Spring提供了多种方式来支持DAO的配置,使得开发人员可以灵活地选择最适合项目需求的数据访问策略。以下将详细阐述Spring对DAO支持...

    Service层和DAO层解析

    Spring框架通过依赖注入(Dependency Injection,DI)实现了这一目标,使得Service层可以通过接口引用DAO层的实现,而不是直接创建DAO实例。这增强了系统的可测试性和可扩展性,因为Service层可以通过配置文件或注解...

Global site tag (gtag.js) - Google Analytics