文档章节

Play源码深入之六:数据库与事务管理

奋斗到天明
 奋斗到天明
发布于 2015/08/27 18:12
字数 769
阅读 761
收藏 0
点赞 0
评论 0

由前面的文章大致知道,Play的事务由过滤器中处理,这里理一下Play框架与数据库相关的部分。 

主要是play.db包中的DBPlugin/DB类,与play.db.jpa包中的JPAPlugin/JPA类有关,前者管理数据源,后者管理JPA。另外因为play是基于ActiveRecord模型,在play.db.jpa.JPAEnhancer类中,play织入了许多辅助方法。 

DBPlugin/JPAPlugin类属于PlayPlugin子类,在play发出的事件中处理相关操作。因为DBPlugin的index比JPAPlugin的大,所以DBPlugin的事件处理会在JPAPlugin的前面。这里需要注意play处理顺序,在前半部分请求是从0到100000,后半部分响应时是从100000到0处理,所以整个处理过程是0、100、1000、...1000、100、0。

0:play.CorePlugin
100:play.data.parsing.TempFilePlugin
200:play.data.validation.ValidationPlugin
300:play.db.DBPlugin
400:play.db.jpa.JPAPlugin
450:play.db.Evolutions
500:play.i18n.MessagesPlugin
600:play.libs.WS
700:play.jobs.JobsPlugin
100000:play.plugins.ConfigurablePluginDisablingPlugin

从配置文件中加载数据源主要发生在onApplicationStart,并可配置多个数据源。在配置数据源的时候,play会试探性连接,用来判断数据源是否可用。

public class DBPlugin extends PlayPlugin {  
    @Override
    public void onApplicationStart() {
        if (changed()) {
            String dbName = "";
            try {
                ...
                Set dbNames = Configuration.getDbNames();
                Iterator it = dbNames.iterator();
                while(it.hasNext()) {
                    dbName = it.next();
                    ...

                    if (isJndiDatasource || datasourceName.startsWith("java:")) {
                        ... 
                    } else {
                        ...
                        url = ds.getJdbcUrl();
                        Connection c = null;
                        try {
                            c = ds.getConnection();
                        } finally {
                            if (c != null) {
                                c.close();
                            }
                        }
                        Logger.info("Connected to %s for %s", ds.getJdbcUrl(), dbName);
                        DB.datasources.put(dbName, extDs);
                    }
                }
            } catch (Exception e) {
                ...
            }
        }
    }
}

之前写过一篇基于play 1.2.3的多数据库文章: 多数据库切换。 JPAPlugin中,处理逻辑较多。主要集中在下面四个方法:

public class JPAPlugin extends PlayPlugin {
    @Override
    public Object bind(RootParamNode rootParamNode, String name, Class clazz, java.lang.reflect.Type type, Annotation[] annotations) {....}

    @Override
    public void enhance(ApplicationClass applicationClass) throws Exception {...}

    @Override
    public void onApplicationStart() {...}

    @Override
    public Filter getFilter() {...}
}

bind方法,将请求中域对象加入HibernateSession之中。 

enhance方法,为基于play.db.jpa.JPABase的子Model织入相应辅助代码。 

onApplicationStart方法,根据数据配置实例工厂。 

getFilter方法,获取过滤器,这里就是事务相关的过滤器。 

在play.db.jpa.JPA:withTransaction()方法中,可以看出,play已经可以同时管理多个数据库的事务,在1.2.3版本这是没有见过。

public class JPA {
    public static  T withTransaction(String dbName, boolean readOnly, F.Function0 block) throws Throwable {
        if (isEnabled()) {
            boolean closeEm = true;
            // For each existing persisence unit
           
            try {
                // we are starting a transaction for all known persistent unit
                // this is probably not the best, but there is no way we can know where to go from
                // at this stage
                for (String name : emfs.keySet()) {
                    EntityManager localEm = JPA.newEntityManager(name);
                    JPA.bindForCurrentThread(name, localEm, readOnly);

                    if (!readOnly) {
                        localEm.getTransaction().begin();
                    }
                }

                T result = block.apply();
              
                boolean rollbackAll = false;
                // Get back our entity managers
                // Because people might have mess up with the current entity managers
                for (JPAContext jpaContext : get().values()) {
                    EntityManager m = jpaContext.entityManager;
                    EntityTransaction localTx = m.getTransaction();
                    // The resource transaction must be in progress in order to determine if it has been marked for rollback
                    if (localTx.isActive() && localTx.getRollbackOnly()) {
                        rollbackAll = true;
                    }
                }

                for (JPAContext jpaContext : get().values()) {
                    EntityManager m = jpaContext.entityManager;
                    boolean ro = jpaContext.readonly;
                    EntityTransaction localTx = m.getTransaction();
                    // transaction must be active to make some rollback or commit
                    if (localTx.isActive()) {
                        if (rollbackAll || ro) {
                            localTx.rollback();
                        } else {
                            localTx.commit();
                        }
                    }
                }
                return result;
            } catch (...) {
                
            } finally {
                ...
            }      
        } else {
            return block.apply();
        }
    }
}

对于每个数据库实例逐一开启事务,处理用户代码之后,检查每个实例,如果有一个回滚,则所有事务都回滚,如果没有则逐一提交。 

虽然Play2.x已经横在前方,但是Play1.x还在演进,我想这是所有Play1.x用户所期望的。

© 著作权归作者所有

共有 人打赏支持
奋斗到天明
粉丝 18
博文 112
码字总数 82707
作品 0
昌平
程序员
Play源码解析计划

最近有想法看看Play的源码,以提高自己的编码水平。之前都是东看看,西看看。最后看来去却好像无所大成。有人说过,伤敌十指,不如断敌一指,于是我有开始了学习之路。 原计划是采用1.2.3版本...

刀狂剑痴 ⋅ 2015/08/27 ⋅ 0

Play源码深入之五:Job模块的原理

先看play.jobs.JobsPlugin。 public void onApplicationStart() { int core = Integer.parseInt(Play.configuration.getProperty("play.jobs.pool", "10")); executor = new ScheduledThread......

刀狂剑痴 ⋅ 2015/08/27 ⋅ 0

Play 1.x框架学习之七:多数据库切换与源码修改 ( Databases Switch And Modify Source Code)

在单数据源(单个ip)下的多库,可以使用use xxdb 命令进行切换,但是如果多个数据源的情况下,use命令就不行了。在play框架中,提供了多数据源多库的切换。本文不提供完全的例子,只提供部分...

刀狂剑痴 ⋅ 2015/08/27 ⋅ 0

Play 1.x框架学习之一:功能测试 (functional test in play framework)

Play框架中已经集成了junit框架,大家可以非常方便的进行功能测试,这里我展现一个测试新增的例子,其他的大家可以照这个例子深入。 首先需要在app/modules包中定义一个Beat类,app/control...

刀狂剑痴 ⋅ 2015/08/27 ⋅ 0

spring mvc 数据库方面如何处理并发的?

看了ThreadLocal,了解其应用的场景多在数据库连接,事务管理方面,并在spring,hibernate的源码中有广泛运用。所以,这里在没有看源码的基础上,有个疑问:spirng mvc项目在连接数据库时都是根...

安静的敲代码 ⋅ 2016/05/26 ⋅ 8

深入Spring:自定义事务管理

前言 上一篇文章讲了Spring的Aop,这里讲一下Spring的事务管理,Spring的事务管理是建立在Aop的基础上的,相比Aop,事务管理的实现耦合性比较小,自定义就比较简单了。 自定义事务 Spring的开...

wcong ⋅ 2016/05/18 ⋅ 2

spring 声明事物

采用的基本搭建环境:SpringMVC、MyBatis、MySQL、tomcat Spring事务管理分解了传统的全局事务管理和本地事务管理的劣势,使得在任何环境中都可以使用统一的事务管理模型,你可以写一次代码,...

訫犫 ⋅ 2016/01/15 ⋅ 0

Spring源码学习之:spring注解@Transactional

在分析深入分析@Transactional的使用之前,我们先回顾一下事务的一些基本内容。 事务的基本概念 先来回顾一下事务的基本概念和特性。数据库事务(Database Transaction) ,是指作为单个逻辑工...

无信不立 ⋅ 2016/10/13 ⋅ 0

Spring事务隔离级别与传播机制,spring+mybatis+atomikos实现分布式事务管理

本文转载于本人另一博客【http://blog.csdn.net/liaohaojian/article/details/68488150】 1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,...

半山闲人 ⋅ 2017/04/13 ⋅ 0

Play框架拾遗之四:域模型与JPA支持

1、属性模拟 对于model,Play中字段都是public修饰符,但框架会自动生成setter与getter如: @Entity@Table(name="product ")public class Product extends BaseModel{ @Id public Long id; ......

刀狂剑痴 ⋅ 2015/08/27 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JDK1.6和JDK1.7中,Collections.sort的区别,

背景 最近,项目正在集成测试阶段,项目在服务器上运行了一段时间,点击表格的列进行排序的时候,有的列排序正常,有的列在排序的时候,在后台会抛出如下异常,查询到不到数据,而且在另外一...

tsmyk0715 ⋅ 26分钟前 ⋅ 0

spring RESTful

spring RESTful官方文档:http://spring.io/guides/gs/rest-service/ 1. 可以这么去理解RESTful:其实就是web对外提供的一种基于URL、URI的资源供给服务。不是一个原理性知识点。是一个方法论...

BobwithB ⋅ 28分钟前 ⋅ 0

C++ 中命名空间的 5 个常见用法

相信小伙伴们对C++已经非常熟悉,但是对命名空间经常使用到的地方还不是很明白,这篇文章就针对命名空间这一块做了一个叙述。 命名空间在1995年被引入到 c++ 标准中,通常是这样定义的: 命名...

柳猫 ⋅ 31分钟前 ⋅ 0

@Conditional派生注解

@Conditional派生注解(Spring注解版原生的@Conditional作用) 作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效; @Conditional扩展注解 作用(判...

小致dad ⋅ 32分钟前 ⋅ 0

适配器模式

适配器模式 对象适配器 通过私有属性来实现的类适配器 通过继承来实现的接口适配器 通过继承一个默认实现的类实现的

Cobbage ⋅ 35分钟前 ⋅ 0

Java 限流策略

概要 在大数据量高并发访问时,经常会出现服务或接口面对暴涨的请求而不可用的情况,甚至引发连锁反映导致整个系统崩溃。此时你需要使用的技术手段之一就是限流,当请求达到一定的并发数或速...

轨迹_ ⋅ 39分钟前 ⋅ 0

GridView和子View之间的间隙

默认的情况下GridView和子View之间会有一个间隙,原因是GridView为了在子View被选中时在子View周围显示一个框。去掉的办法如下: android:listSelector="#0000" 或 setSelector(new ColorDra...

国仔饼 ⋅ 42分钟前 ⋅ 0

idea插件开发

1 刷新页面要使用多线程 2 调试要使用restart bug 不要去关闭调试的idea 否则再次启动会卡住

林伟琨 ⋅ 42分钟前 ⋅ 0

Java 内存模型

物理机并发处理方案 绝大多数计算任务,并不是单纯依赖 cpu 的计算完成,不可避免需要与内存交互,获取数据。内存要拿到数据,需要和硬盘发生 I/O 操作。计算机存储设备与 cpu 之间的处理速度...

长安一梦 ⋅ 49分钟前 ⋅ 0

思路分析 如何通过反射 给 bean entity 对象 的List 集合属性赋值?

其实 这块 大家 去 看 springmvc 源码 肯定可以找到实现办法。 因为 spirngmvc 的方法 是可以 为 对象 参数里面的 list 属性赋值的。 我也没有看 具体的 mvc 源码实现,我这里只是 写一个 简...

之渊 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部