锁定老帖子 主题:一个支持数据库分布式访问的小框架(更新5)
精华帖 (0) :: 良好帖 (9) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2012-05-02
最后修改:2012-06-04
最近写了一个支持分布式数据库访问的小框架,只要是使用PreparedStatement进行sql处理的框架都可以结合使用。例如 hibernate ,ibatis,mybatis。
支持分表分库,单数据库事务支持,多数据库事务分布提交(只是自动多次con.commit(),并不具有真正的分布式事务功能)。
代码在 https://github.com/akwei/halo-dal 目前本人还不会使用maven进行包管理,所以需要的jar包都放到了代码中。
以后会加入读写分离的数据访问方式 欢迎大家多提意见
我的新浪微博是 @akweiwei,gtalk:ak478288@gmail.com qq:54501421
欢迎交流
更新: 对代码进行了优化 已经增加支持读写分离的解析 修改了例子 可以通过代码指定数据源和表,适用于一些无法通过条件进行解析的场景(感谢"程序新手",发现我原先没有对此场景支持)
更新2: 新版本已经发布,目前支持sql解析器结果缓存,这样就不用每次都进行解析了。只需要进行替换表名称。目前还没有实现使用antlr进行解析。
更新3: 修改了多处bug,谢谢大家在使用中提出的意见,以及找出的bug,目前本人时间有限,测试用例写的不完美。感谢大家帮助我测试。
更新4: 在使用sequenece作为id时,请求sequenece的sql语句是没有任何库表信息的。因此会抛出dsKey 为null 的异常。因此在使用时,请尽量先通合适的方式获得最新id。 不在分表分库的操作中首先使用sequence操作。
更新5:
修改DALConnection isClosed 方法,当未指定数据源时报错。增加了没有数据源时请求的判断。 目前发现在使用hibernate时会遇到此问题。在mysql中当不使用自增id时,hibernate会获取connection进行一些判断。
小节一下: 有朋友提出了一些会出现的场景:例如需要对每个节点都要操作,那么无法通过查询条件或者赋值条件来指定解析。这种情况只能说是与业务结合,进行具体的处理操作了。 目前文档还不够完善,没把如何直接指定数据源的操作写出来。如果直接指定数据源,就能实现对每个节点的操作。 感谢 "程序新手"提出的场景。 也希望大家多多挑刺,提出不同的场景,看看能否实现 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2012-05-02
对这两点感兴趣:
1、如何支持分库分表的 2、如何支持xa的 |
|
返回顶楼 | |
发表时间:2012-05-02
kimmking 写道 对这两点感兴趣:
1、如何支持分库分表的 2、如何支持xa的 目前做不做分布式事务,我写的说明可能有问题,抱歉 支持分库分表,原理是自己包装了Connection PreparedStatement DataSource,进行数据库连接延迟加载方式 例如 当使用Spring 配置service事务,service.method运行时,spring事务组件会开启数据库事务,这个时候开启的并不是真正的数据库Connection,而是我包装的一个不具有任何数据库特征的Connection,我类名为DALConnection,当进行PreparedStatement操作时,也是如此,操作的都是DALPreparedStatement,真正进行execute()方法时,这个时候程序进行sql解析,获得条件表达式与值,然后与数据路由规则进行匹配,找到真正的数据源,并开启Connection,创建与数据库连接的PreparedStatement,并把刚才一切对DALConnection , DALPreparedStatement进行的操作真正的执行一遍。 使用时与普通的jdbc hibernate等没有区别,只是多了需要编写路由规则程序的步骤而已。 |
|
返回顶楼 | |
发表时间:2012-05-02
如何路由呢?
就是说对建表有什么要求,对sql有什么要求,如何路由 |
|
返回顶楼 | |
发表时间:2012-05-02
kimmking 写道
如何路由呢?
就是说对建表有什么要求,对sql有什么要求,如何路由
和普通建表方式没有区别。
简单举例:
sql: select * from user where level=1 order by xxxx;
假如需要根据level的值进行分表,那么level条件就需要在表达式中,并且有值.
sql解析器就会解析sql,并获得所有表达式的值。
然后把分析结果传递给相应的路有规则解析器,解析器就会分析表达式中的值,来判断到哪里获取数据。
解析器举例:
package parser; import halo.dal.partition.DALPartitionParser; import halo.dal.partition.DALPartitionTableInfo; import halo.dal.partition.analysis.SQLExpression; import halo.dal.partition.analysis.SQLExpressionSymbol; import halo.dal.partition.analysis.SQLInfo; /** * 对user表进行分区,根据奇偶方式,将偶数sex放入daltest0.user0, 奇数sex放入daltest1.user1 * * @author akwei */ public class UserParser implements DALPartitionParser { public DALPartitionTableInfo parse(String tableLogicName, SQLInfo sqlInfo) { DALPartitionTableInfo info = new DALPartitionTableInfo(); // 从sqlInfo获得条件表达式,由于定义的分区条件为sex字段,那么就需要获取sex字段的表达式 // /由于获取的表达式会存在多个,例如进行范围判断的情况下,就会出现2个表达式,因此会返回一个数组 SQLExpression[] sqlExpressions = sqlInfo.getSQLExpressions("sex"); for (SQLExpression e : sqlExpressions) { // sex表达式我们只需要获得sex=?的等号表达式 if (e.getSqlExpressionSymbol() == SQLExpressionSymbol.EQUAL) { Integer l = (Integer) e.getValue(); // 获得表达式的值之后,进行奇偶判断,判断的结果就是我们获得的真实数据源key与表名称 // 数据源key就是在创建DALDataSource的时候,写入map的key,这个key与真实的DataSource一一对应 if (l.intValue() % 2 == 0) { info.setRealTableName("user0");// 真实数据表名称 info.setDsName("ds0");// 真实数源key } else { info.setRealTableName("user1");// 真实数据表名称 info.setDsName("ds1");// 真实数源key } } } return info; } } |
|
返回顶楼 | |
发表时间:2012-05-02
kimmking 写道 如何路由呢?
就是说对建表有什么要求,对sql有什么要求,如何路由 解析器的编写,并不会入侵到业务代码中 |
|
返回顶楼 | |
发表时间:2012-05-02
思路和我的freyja相识
http://freyja.iteye.com/blog/1412191、 不过经过封装,只需要在需要分库的用annotation标记就行了,执行sql的时候会解析表达式,然后根据annotation注解确定其所在的库、表。 |
|
返回顶楼 | |
发表时间:2012-05-02
ps。分库分表功能是当前一个项目用到的还未完善,一些嵌套sql等支持不好。但是支持的sql包括jdbc Statement
因为解析sql用的是jsqlparser 所以支持大部分sql语句 |
|
返回顶楼 | |
发表时间:2012-05-02
我的读写分离 基于spring+mybatis,大致一样也是基于lazyconnectionProxy。
http://xiaoz5919.iteye.com/blog/1497223 |
|
返回顶楼 | |
发表时间:2012-05-02
看来对这个东西,大家都挺感兴趣,而且动手实践过。
|
|
返回顶楼 | |