大家都知道,现在的互联网后端服务总共分3层:dao层、service层和controller层。今天我们来学习一下dao层与service层之间的数据访问问题,看看它们之间是怎么交互的。
dao层与service层之间的交互,简单说来,就是service层会去调用dao层,而在调用dao层的时候就必然要用到事务。有些新手朋友在初次写后端程序的时候,往往不知道这里有事务问题,以为就像直接调用API一样,调用一次insert/update/delete操作就修改一次数据库,十分简单明了,而且测试也没发现问题,一切正常。其实这样写的程序主要运行在内网、小规模系统环境中,甚至单机运行,这对数据一致性要求不那么高,所以未出错。但是一旦部署到线上高并发运行环境中去,数据很有可能不一致,这是因为没有处理好事务。
另外,后端服务DAO层一般是接入或使用了ORM框架的,例如Hibernate、JPA、MyBatis等。这些框架主要目的是减少样板代码,提高开发效率。这些不同ORM框架的设计差异很大,却能被Spring框架定义成一套通用的接口,封装起来供我们使用(题外话:不得不说,Spring开发者的抽象化和设计能力真的非常强,值得学习)。
Spring 事务管理
spring的事务管理特别强大,优势如下:
统一的编程模型支持多种不同的事务API,包括JTA、JDBC、Hibernate、JPA等。
声明式事务管理功能:即只需要声明,加一个注解就搞定一切了。让事务功能用起来简单。
编程式事务管理:Spring对底层的事务API进行了抽象和简化。
能够高效集成到Spring的数据访问抽象架构中去,即Spring里面的DAO。
Spring事务模型
真正的高手是如何解决问题的?他们不是见到一个问题就写一段代码,然后再加上一大堆的条件判断来限制使用场景。这种解决问题的方式是很原始的。高手则是全面分析问题,把问题中出现的事情进行抽象化,形成一个个的概念,然后再建立起一套模型,把问题统统归类到新建立起的模型上,最后再针对模型来进行分析、求解和计算。
Spring为了把不同的底层事务API统一,就建立了一个模型,我们姑且叫它为Spring事务模型吧。Spring事务模型是怎么得来的呢?从Java EE中的全局事务和局部事务发展而来。
在Spring之前,后端服务是基于Java EE的。而在Java EE中,数据库事务功能只有2个选择:1. 全局事务 2.本地事务。
Java EE 全局事务
Java EE中的全局事务可以管理多个事务资源,例如关系数据库和消息队列,是跨多台机器的,也就是所谓的“分布式事务”。业务服务器通过JTA管理全局事务(API复杂、难用),而且其中用到的UserTransaction必须是从JNDI拿到,导致必须使用JNDI技术。
Java EE 局部事务
局部事务只能管理一个事务资源,不能跨机器,且应用服务器不参与事务管理。大部分流量小的或内网访问的数据管理系统,使用的是局部事务。
理解Spring框架事务抽象
事务策略(transaction strategy):这是理解Spring事务抽象的关键。事务策略由TransactionManager定义。
调用TransactionManager#getTransaction,可以传入TransactionDefinition,可以得到TransactionStatus。
TransactionStatus:代表了一个新创建的事务或者已经存在的事务。
TransactionDefinition:指定各种与事务相关的信息。
传播性 (propagation):凡是在事务范围内的代码,都是在这个事务内运行的。对于一段事务代码来说,假如一个事务已经存在了,需要用传播性来指定是:继续使用已经存在的事务还是把已经存在的事务suspend然后再新建一个事务(Spring事务传播性的概念其实来自EJB CMT,共有5个,可以在TransactionDefinition的源码中找到)
隔离性(isolation):当前事务与其他事务的隔离的程度。例如,当前事务能够访问到其他事务的还没有提交的数据(参考Isolation枚举类)。
超时(timeout):事务执行了多长时间之后依然还没有完成,则自动回滚。
只读(read-only):如果事务只读不修改数据,则可以利用这个参数优化性能。
上面4项是事务的核心概念,也是后端程序员必然要掌握的基础知识(面试当然会问),掌握不好的话,写出来的代码访问数据库的时候会出问题。
TransactionStatus可以用于控制事务的运行,还可以查询事务的状态。
TransactionManager负责执行事务,它与底层用到的数据库框架相关,例如JDBC、JTA、Hibernate分别对应不同的事务管理器(事务管理器)。一般都是Spring预先写好的。例如,如果底层是通过JDBC访问数据库的,那么事务管理器应该用 DataSourceTransactionManager。TransactionManager一般需要依赖一个DataSource,而DataSource一般提供与数据库相关的更加底层的信息,包括jdbcref、用户名、密码等等。
到这里,你的认知应该有以下迭代了:
希望这篇文章能对您有帮助!如果您对互联网、前/后/客户端、架构/分布式/高可用/高并发/高实时、电商、Redis、MySQL、Zookeeper、Spring、Android、浏览器插件、Java、C/C++、Linux、个性化推荐、社区发现、机器学习、数据挖掘等感兴趣,欢迎关注。