`
wuhuajun
  • 浏览: 92175 次
  • 性别: 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
分享到:
评论

相关推荐

    Scrapy-1.8.2.tar.gz

    文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    search-log.zip

    搜索记录,包括时间、搜索关键词等,用于PySpark案例练习

    6-12.py

    6-12

    2-6.py

    2-6

    Scrapy-0.24.5-py2-none-any.whl

    文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    基于CS的远程监控系统软件项目(免费提供全套java开源项目源码+论文)

    项目介绍 背景 在当今的数字化时代,远程监控系统已经成为企业和个人必不可少的工具。随着物联网(IoT)技术的发展,监控系统的需求不断增加,不仅仅局限于视频监控,还包括数据监控、设备状态监控等。基于CS(Client-Server)架构的远程监控系统应运而生,旨在提供高效、实时、可靠的监控服务,帮助用户实现远程管理和控制。 目的 基于CS的远程监控系统软件项目旨在为用户提供一个综合性的监控平台,通过该平台,用户可以实时监控各类设备和数据,实现远程控制和管理,提高工作效率,降低运营成本。同时,该系统还可以用于安全防护、生产过程监控等多种场景,具有广泛的应用前景。 模块说明 前端模块 前端模块是用户与系统交互的界面,负责展示监控数据和接收用户指令。前端模块的主要功能包括: 用户登录与认证:通过安全的登录机制,确保只有授权用户才能访问系统。 实时数据展示:以图表、仪表盘等形式展示实时监控数据,包括视频流、传感器数据等。 报警通知:当监控系统检测到异常情况时,前端模块会通过弹窗、声音等方式通知用户。 远程控制:用户可以通过前端界面对设备进行远程控制,例如开关设备、调整参数等。

    课程大作业二手车价格预测案例数据挖掘python源码+数据集+实验报告+详细注释.zip

    课程大作业二手车价格预测案例数据挖掘python源码+数据集+实验报告+详细注释.zip

    基于springcloud和vue后台管理系统.zip

    springcloud 基于springcloud和vue后台管理系统.zip

    基于Pyotrch的深度学习物体分类可视化系统源码+预训练模型+详细训练教程.zip

    基于Pyotrch的深度学习物体分类可视化系统源码+预训练模型+详细训练教程.zip

    pytest-3.0.2.tar.gz

    文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    XXX公司组织结构诊断报告.ppt

    XXX公司组织结构诊断报告.ppt

    3-18-1.py

    3-18-1

    ZCU102 FPGA DDR4 MIG IP核读写接口封装与FIFO测试工程教程(配套下载资料)

    本资源提供了一份全面的教程,专注于使用ZCU102 FPGA开发板实现DDR4内存的读写操作。通过构建DDR4的MIG(Memory Interface Generator)IP核,本教程详细介绍了如何封装DDR4的读写时序,并创建了一个类似FIFO(先进先出)的接口,以优化数据流的管理和控制。此外,还包含了对所封装接口进行测试的工程实例,帮助开发者深入理解DDR4内存接口的高效应用。适合希望在FPGA项目中集成高效内存管理方案的工程师和高级学者。

    课程设计基于matlab机械臂末端轨迹规划的源码.zip

    课程设计基于matlab机械臂末端轨迹规划的源码.zip

    基于深度学习的LSTM算法双色球预测实战完整代码.zip

    基于深度学习的LSTM算法双色球预测实战完整代码.zip

    yolov5-face-landmarks-opencv

    yolov5检测人脸和关键点,只依赖opencv库就可以运行,程序包含C++和Python两个版本的。 本套程序根据https://github.com/deepcam-cn/yolov5-face 里提供的训练模型.pt文件。转换成onnx文件, 然后使用opencv读取onnx文件做前向推理,onnx文件从百度云盘下载,下载 链接:https://pan.baidu.com/s/14qvEOB90CcVJwVC5jNcu3A 提取码:duwc 下载完成后,onnx文件存放目录里,C++版本的主程序是main_yolo.cpp,Python版本的主程序是main.py 。此外,还有一个main_export_onnx.py文件,它是读取pytorch训练模型.pt文件生成onnx文件的。 如果你想重新生成onnx文件,不能直接在该目录下运行的,你需要把文件拷贝到https://github.com/deepcam-cn/yolov5-face 的主目录里运行,就可以生成onnx文件。

    matlab基于Matlab_Simulink的自主水下航行器三维路径跟踪仿真.zip

    matlab基于Matlab_Simulink的自主水下航行器三维路径跟踪仿真.zip

    麦肯锡 - 上海xx集团-完善组织架构,优化管理流程.ppt

    麦肯锡 - 上海xx集团-完善组织架构,优化管理流程.ppt

    pytest-7.3.2.tar.gz

    文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    matlab将MATLAB连接到OpenAI聊天完成API(支持ChatGPT).zip

    matlab将MATLAB连接到OpenAI聊天完成API(支持ChatGPT).zip

Global site tag (gtag.js) - Google Analytics