- 浏览: 314687 次
- 性别:
- 来自: 杭州
最新评论
-
wizard_hu:
[i]引用[img][url][flash=200,200][ ...
使用Eclipse Memory Analyzer进行内存泄漏分析三部曲 -
可爱的小狗:
学习了
HttpClient容易忽视的细节——连接关闭 -
xiajunhust:
sqtds 写道文章写的很好,浅显易懂!!! com.taob ...
使用Eclipse Memory Analyzer进行内存泄漏分析三部曲 -
zhylandroid:
使用Eclipse Memory Analyzer进行内存泄漏分析三部曲 -
dsjt:
悲剧啊,google code 被墙了
mybatis3分表插件shardbatis 2.0
最近想在自己的项目里实现DB sharding功能,正好前段时间研究过ibatis的源码于是就在ibatis的基础上进行了一些修改。另一方面也是为了练练手。这个sharding的实现主要是基于我项目中的需求实现的可能有很多考虑不周的地方,希望各位大牛拍砖。如果有人感兴趣愿意一起来发展这个项目,本人也非常欢迎各位的加入。
Shardbatis是在mybatis 2.3.5代码的基础上进行一些扩展实现数据水平切分功能。 数据的水平切分包括多数据库的切分和多表的数据切分。目前shardbatis已经实现了单数据库的数据多表水平切分
mybatis2.3.5的核心类图(包含了spring对ibatis的封装SqlMapClientTemplate)如下(其他版本的ibatis的类图有略微不同)
改造后的类图
从这两张图上可以看出shardbatis里新增了接口SqlMapShardingExt,SqlMapShardingExt中具体的方法如下
通过SqlMapClientImpl和SqlMapSessionImpl对SqlMapShardingExt的实现是的ibatis具有了DB sharding的功能,iBATIS会自动根据配置的或者是编码的sharding策略将原始的sql语句转变为对应目标表名的sql。
下面看一下如何在iBATIS中配置和使用sharding功能
1.配置sharding策略。在sql-map-config.xml中添加如下配置
这里再通过实例简单介绍一下使用DefaultShardingStrategy时对sql的convert结果
比如sqlmap中定义的原始sql为:
那经过convert后的结果将可能是
又例如原始sql为
convert的结果可能为
开始使用sharding api
实现自己的sharding策略,只要实现一个简单的接口即可
Since 0.9.1使用ibatis原生api也可以支持sharding功能
下面开始编码
最终执行的SQL可能是如下样式
关于shardbatis在spring中的使用方法,以及一些使用注意事项和性能测试结果请大家移步到项目主页http://code.google.com/p/shardbatis/上查看
数据库水平切分是有特定的场景的,我做这个的目的不是为了解决水平切分的局限性。我做这个的目的是为了通过ibatis实现数据库水平切分的功能。
至于测试方法有不可靠的地方请您不吝赐教,谢谢!
性能测试结果在项目主页中有写,这里再列一下
50个线程并发,每个线程循环执行100次数据库(h2数据库)查询。
下面的测试结果建议关注两种场景的比较值,而不是关注某个具体值(你懂的)
jdk:1.5.0_22 无jvm参数
平均每次查询耗时,单位:毫秒
Shardbatis是在mybatis 2.3.5代码的基础上进行一些扩展实现数据水平切分功能。 数据的水平切分包括多数据库的切分和多表的数据切分。目前shardbatis已经实现了单数据库的数据多表水平切分
mybatis2.3.5的核心类图(包含了spring对ibatis的封装SqlMapClientTemplate)如下(其他版本的ibatis的类图有略微不同)
改造后的类图
从这两张图上可以看出shardbatis里新增了接口SqlMapShardingExt,SqlMapShardingExt中具体的方法如下
public interface SqlMapShardingExt extends SqlMapExecutor{ /** * 带有sharding功能的insert * @param id * @param parameterObject * @param groups * @return * @throws SQLException */ Object insertWithSharding(String id, Object parameterObject, ShardingFactorGroup... groups) throws SQLException; /** * 带有sharding功能的insert * @param id * @param groups * @return * @throws SQLException */ Object insertWithSharding(String id, ShardingFactorGroup... groups) throws SQLException; /** * 带有sharding功能的update * @param id * @param parameterObject * @param groups * @return * @throws SQLException */ int updateWithSharding(String id, Object parameterObject, ShardingFactorGroup... groups) throws SQLException; /** * 带有sharding功能的update * @param id * @param groups * @return * @throws SQLException */ int updateWithSharding(String id, ShardingFactorGroup... groups) throws SQLException; /** * 带有sharding功能的delete * @param id * @param parameterObject * @param groups * @return * @throws SQLException */ int deleteWithSharding(String id, Object parameterObject, ShardingFactorGroup... groups) throws SQLException; /** * 带有sharding功能的delete * @param id * @param groups * @return * @throws SQLException */ int deleteWithSharding(String id, ShardingFactorGroup... groups) throws SQLException; /** * 带有sharding功能的单记录查询 * @param id * @param parameterObject * @param groups * @return * @throws SQLException */ Object queryForObjectWithSharding(String id, Object parameterObject, ShardingFactorGroup... groups) throws SQLException; /** * 带有sharding功能的单记录查询 * @param id * @param groups * @return * @throws SQLException */ Object queryForObjectWithSharding(String id, ShardingFactorGroup... groups) throws SQLException; /** * 带有sharding功能的单记录查询 * @param id * @param parameterObject * @param resultObject * @param groups * @return * @throws SQLException */ Object queryForObjectWithSharding(String id, Object parameterObject, Object resultObject, ShardingFactorGroup... groups) throws SQLException; /** * 带有sharding功能的查询 * @param id * @param parameterObject * @param groups * @return * @throws SQLException */ List queryForListWithSharding(String id, Object parameterObject, ShardingFactorGroup... groups) throws SQLException; /** * 带有sharding功能的查询 * @param id * @param groups * @return * @throws SQLException */ List queryForListWithSharding(String id, ShardingFactorGroup... groups) throws SQLException; /** * 带有sharding功能的查询 * @param id * @param parameterObject * @param skip * @param max * @param groups * @return * @throws SQLException */ List queryForListWithSharding(String id, Object parameterObject, int skip, int max, ShardingFactorGroup... groups) throws SQLException; /** * 带有sharding功能的查询 * @param id * @param skip * @param max * @param groups * @return * @throws SQLException */ List queryForListWithSharding(String id, int skip, int max, ShardingFactorGroup... groups) throws SQLException; /** * * @param id * @param parameterObject * @param rowHandler * @param groups * @throws SQLException */ void queryWithRowHandlerWithSharding(String id, Object parameterObject, RowHandler rowHandler, ShardingFactorGroup... groups) throws SQLException; /** * * @param id * @param rowHandler * @param groups * @throws SQLException */ void queryWithRowHandlerWithSharding(String id, RowHandler rowHandler, ShardingFactorGroup... groups) throws SQLException; /** * * @param id * @param parameterObject * @param keyProp * @param groups * @return * @throws SQLException */ Map queryForMapWithSharding(String id, Object parameterObject, String keyProp, ShardingFactorGroup... groups) throws SQLException; /** * * @param id * @param parameterObject * @param keyProp * @param valueProp * @param groups * @return * @throws SQLException */ Map queryForMapWithSharding(String id, Object parameterObject, String keyProp, String valueProp, ShardingFactorGroup... groups) throws SQLException;
通过SqlMapClientImpl和SqlMapSessionImpl对SqlMapShardingExt的实现是的ibatis具有了DB sharding的功能,iBATIS会自动根据配置的或者是编码的sharding策略将原始的sql语句转变为对应目标表名的sql。
下面看一下如何在iBATIS中配置和使用sharding功能
1.配置sharding策略。在sql-map-config.xml中添加如下配置
<shardingConfig> <!-- 对于app_test使用默认的切分策略,默认的切分策略只是简单按数值取模生成新的表名,如何实现切分策略后面再介绍 --> <sharding tableName="app_test" strategyClass="com.ibatis.sqlmap.engine.sharding.impl.DefaultShardingStrategy"/> <!-- 没有配置切分策略等于使用默认的切分策略 --> <sharding tableName="app_2test" /> </shardingConfig>
这里再通过实例简单介绍一下使用DefaultShardingStrategy时对sql的convert结果
比如sqlmap中定义的原始sql为:
SELECT EMPLOYEEIDNO FROM mytable WHERE SALARY >= 50000
那经过convert后的结果将可能是
SELECT EMPLOYEEIDNO FROM mytable_1 WHERE SALARY >= 50000
又例如原始sql为
SELECT a.* FROM ANTIQUES a,ANTIQUEOWNERS b, mytable c where a.id=b.id and b.id=c.id
convert的结果可能为
SELECT a.* FROM ANTIQUES_0 AS a, ANTIQUEOWNERS_1 AS b, mytable_1 AS c WHERE a.id = b.id AND b.id = c.id
开始使用sharding api
public class SqlMapClientTest { SqlMapClient sqlMapper; @Before public void init() { Reader reader; try { reader = Resources.getResourceAsReader("sql-map-config.xml"); sqlMapper = SqlMapClientBuilder.buildSqlMapClient(reader); reader.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Test public void testSharding() throws Exception { Map param = new HashMap(); param.put("cnt", "ttt"); ShardingFactorGroup g = new ShardingFactorGroup();//ShardingFactorGroup为切分策略提供必要参数 g.setTableName("App_Test");//设置为哪张表配置切分策略 g.setParam(new Integer(123));//设置为切分策略提供参数 //这里还可以通过g.setShardingStrategy(...)来设置切分策略 //通过API配置的切分策略可以覆盖xml里配置的App_Test表的切分策略 Integer count = (Integer) sqlMapper.queryForObjectWithSharding( "AppTest.select_paging_count_by_map", param, g); Assert.assertEquals(count.toString(), "0"); } @Test public void testUpdate() throws SQLException { ShardingFactorGroup g = new ShardingFactorGroup(); g.setTableName("App_Test"); g.setParam(new Integer(123)); String cnt = "testUpdate" + System.currentTimeMillis(); AppTest at1 = new AppTest(); at1.setCnt(cnt); Integer id = (Integer) sqlMapper.insertWithSharding( "AppTest.insert_h2", at1, g); AppTest parameterObject = new AppTest(); parameterObject.setCnt(cnt); AppTest ret = (AppTest) sqlMapper.queryForObjectWithSharding( "AppTest.select_by_condition", parameterObject, g); Assert.assertEquals(ret.getId().toString(), id.toString()); ret.setCnt("NEW_CONTENT"); Integer count = sqlMapper.updateWithSharding("AppTest.update", ret, g); Assert.assertEquals(count.toString(), "1"); count = (Integer) sqlMapper.queryForObjectWithSharding( "AppTest.select_paging_count", ret, g); Assert.assertEquals(count.toString(), "1"); } @Test public void testDelete() throws SQLException { ShardingFactorGroup g = new ShardingFactorGroup(); g.setTableName("App_Test"); g.setParam(new Integer(123)); String cnt = "testDelete" + System.currentTimeMillis(); AppTest at1 = new AppTest(); at1.setCnt(cnt); Integer id = (Integer) sqlMapper.insertWithSharding( "AppTest.insert_h2", at1, g); AppTest parameterObject = new AppTest(); parameterObject.setCnt(cnt); AppTest ret = (AppTest) sqlMapper.queryForObjectWithSharding( "AppTest.select_by_condition", parameterObject, g); Assert.assertEquals(ret.getId().toString(), id.toString()); Integer row = sqlMapper.deleteWithSharding("AppTest.delete", ret, g); Assert.assertEquals(row.toString(), "1"); } }
实现自己的sharding策略,只要实现一个简单的接口即可
public interface ShardingStrategy { /** * 计算得到新的表名 * @param baseTableName 逻辑表名 * @param params 为sharding逻辑提供必要参数 * @return */ public String getTargetTableName(String baseTableName,Object params); }
Since 0.9.1使用ibatis原生api也可以支持sharding功能
<!-- 在sql-map-config.xml中添加如下配置 --> <shardingConfig> <!-- 对于app_test使用默认的切分策略,默认的切分策略只是简单按数值取模生成新的表名,如何实现切分策略后面再介绍 --> <sharding tableName="app_test" strategyClass="com.ibatis.sqlmap.engine.sharding.impl.DefaultShardingStrategy"/> <!-- 没有配置切分策略等于使用默认的切分策略 --> <sharding tableName="app_2test" /> </shardingConfig> <!-- 在sqlmap.xml中statement节点都可以添加shardingParams属性 shardingParams对应的值使用json数组格式, paramExpr 对应parameterClass对象中的某个属性,这个属性的值会传递给sharding策略用于计算新的表名, 例如paramExpr:testId 等同于appTest.getTestId;paramExpr:model.id 等同于appTest.getModel().getId() tableName 用于表示当前这个json对象配使用于sql中的哪个表 strategyClass strateg接口实现类的全名,这个值如果没有将使用sql-map-config.xml里shardingConfig下配置对应的值。 --> <select id="select_count_native" parameterClass="AppTest" resultClass="java.lang.Integer" shardingParams='[{"paramExpr":"testId","tableName":"app_test"}]'> select count(*) from app_test where cnt=#cnt# </select>
下面开始编码
AppTest param=new AppTest(); param.setTestId(2); param.setCnt("testShardingWithConfig"); Integer count=(Integer)sqlMapper.queryForObject("AppTest.select_count_native",param);//和使用原生的ibatis API没有区别
最终执行的SQL可能是如下样式
select count(*) from app_test_0 where cnt=?
关于shardbatis在spring中的使用方法,以及一些使用注意事项和性能测试结果请大家移步到项目主页http://code.google.com/p/shardbatis/上查看
评论
5 楼
SeanHe
2010-09-01
J-catTeam 写道
数据库的水平切分 使用局限性还是有的。比如sql中的分组,排序,或者其他一些情况。
另外 兄弟 你的测试方法应该不是很可靠吧。
另外 兄弟 你的测试方法应该不是很可靠吧。
数据库水平切分是有特定的场景的,我做这个的目的不是为了解决水平切分的局限性。我做这个的目的是为了通过ibatis实现数据库水平切分的功能。
至于测试方法有不可靠的地方请您不吝赐教,谢谢!
4 楼
J-catTeam
2010-09-01
数据库的水平切分 使用局限性还是有的。比如sql中的分组,排序,或者其他一些情况。
另外 兄弟 你的测试方法应该不是很可靠吧。
另外 兄弟 你的测试方法应该不是很可靠吧。
3 楼
SeanHe
2010-09-01
D04540214 写道
性能如何?
性能测试结果在项目主页中有写,这里再列一下
50个线程并发,每个线程循环执行100次数据库(h2数据库)查询。
下面的测试结果建议关注两种场景的比较值,而不是关注某个具体值(你懂的)
jdk:1.5.0_22 无jvm参数
平均每次查询耗时,单位:毫秒
场景 | 20线程 | 30线程 | 50线程 | 50线程use jdk6 |
sharding | 690.721 | 1051.983778 | 1708.146467 | 51584.499067 |
no sharding | 683.75 | 1024.096 | 1704.1314 | 1601.592 |
2 楼
严东军
2010-09-01
支持下。技术型文章就是牛B
1 楼
D04540214
2010-09-01
性能如何?
发表评论
-
mybatis3分表插件shardbatis 2.0
2011-07-23 14:08 22189shardbait2.0实现分表的功能可以用一句话描述:使用m ... -
运行Apache Mahout的Taste Webapp例子
2011-07-14 20:00 10408Apache Mahout 是 Apache Soft ... -
编程式配置Spring bean
2011-02-15 23:29 2585今晚翻看了以前写的RPC框架。发现这个框架中编程式配置Spri ... -
JVM Crash原因分析及相关资料
2011-02-14 15:53 15008去年生产环境突然有一天连续发生几台服务器JVM Crash的情 ... -
一次jboss中部署应用时类版本冲突问题分析、解决过程
2011-02-10 10:11 9993去年同事的一个项目在JBOSS中部署时遇到类版本冲突问题,当时 ... -
java nio学习笔记
2011-01-30 00:37 0通道 和 缓冲区 是 NIO 中的核心对象,几乎在每一个 I/ ... -
使用Eclipse Memory Analyzer进行内存泄漏分析三部曲
2011-01-27 14:40 36697一、准备工作 分析较大的dump文件(根据我自己的经验2G以上 ... -
JBoss、Tomcat Classloader不完全分析
2010-12-14 13:25 3837由于平时项目中用到的还是JBoss 4.2.x所以我这里的分析 ... -
sitemesh性能测试结果比较惊艳(已经补上新的对比测试结果)
2010-07-17 17:03 6753最近想在一个项目中使用sitemesh作为view层的装饰器, ... -
Spring对Quartz的封装实现简单分析及使用注意事项
2010-06-14 14:08 9938前段时间在项目中一直使用正常的Quartz突然出现了任务漏跑的 ... -
Google App Engine for Java 开发笔记
2009-07-25 23:01 1855最近使用GAE开发一个小应用,开发过程中发现几个问题在这里做下 ... -
HttpClient容易忽视的细节——连接关闭
2008-08-30 12:22 130933HttpClient client = new HttpC ... -
为Hessian加入加密签名的安全机制
2008-03-09 10:01 6026Hessian是轻量级的RMI实现使用起来非常的方便,同时与S ... -
java DSA签名实现
2008-03-08 21:50 7235通过以下工具类可以生成DSA公钥和私钥文件 /** * ...
相关推荐
标题 "基于struts+spring+ibatis的轻量级J2EE开发" 指向的是一个关于使用Struts、Spring和iBatis这三种开源框架进行轻量级Java企业级应用开发的主题。这个组合通常被称为SSM(Struts、Spring、MyBatis)框架集成,是...
《基于半自动化iBatis的轻量级ORM改进研究》这一主题聚焦于如何优化和增强iBatis这一轻量级对象关系映射(ORM)框架的自动化程度,以提高开发效率和代码质量。iBatis作为Java开发中的一个流行工具,它允许开发者将...
公司让学的 正在学习
iBatis轻量级持久层架构是Java开发中用于数据库操作的一个流行框架,它提供了灵活的SQL映射机制,能够将SQL语句与Java代码分离,使得代码更易于维护和测试。以下是关于iBatis的一些关键知识点: 1. **Spring嵌套...
Struts、Spring和iBatis是Java开发领域中非常经典的三大框架,它们组合起来可以构建出高效、可维护的轻量级J2EE应用程序。这个压缩包文件"基于struts+spring+ibatis的轻量级J2EE开发.rar"很可能包含了一套完整的示例...
【数据库水平切分实现原理解析】 随着互联网的发展,海量数据的存储与访问已成为系统设计的关键挑战。面对每天数十亿的页面访问量(PV),数据库的高负载问题日益突出,严重影响了系统的稳定性和扩展性。水平切分...
通过SqlMapClient,开发者可以执行查询、插入、更新和删除等操作。 2. **Statement**:代表了一个SQL语句,包括PreparedStatement和SimpleStatement两种类型。PreparedStatement支持预编译,提高性能并防止SQL注入...
Ibatis,全称为MyBatis,是一个优秀的Java持久层框架,它主要负责SQL映射,将数据库操作与业务逻辑解耦,使得开发者可以更专注于业务逻辑的实现,而无需关心繁琐的SQL语句编写。本篇文章将深入探讨Ibatis API、文档...
通过上述步骤,我们可以在ibatis中实现高效的批量更新操作,极大地提升系统处理大规模数据的能力。这种方法不仅适用于Java环境下的开发,也适用于其他支持ibatis的编程语言。总之,ibatis提供的批量更新功能是处理...
通过MyBatis-Spring整合,可以实现事务管理和DAO的注入,使得iBatis更好地融入到Spring框架中。在本项目中,iBatis负责与Oracle数据库的交互,执行CRUD操作。 **Oracle数据库** Oracle是企业级的数据库系统,支持...
这个“ibatis-api中文(真的中文)”资料集合包含了iBATIS的API文档以及教程,帮助开发者更好地理解和使用iBATIS。 首先,`iBATIS-SqlMaps-2-cn.pdf`是iBATIS SQL Maps 2.0的中文版教程。在该文档中,你可以找到...
在Java Web开发中,Ibatis作为一个轻量级的持久层框架,被广泛应用于数据库操作。在处理大量数据时,为了提高用户体验,分页显示数据变得至关重要。本篇将详细讲解如何利用Ibatis实现分页技术。 一、Ibatis简介 ...
Ibatis 是一款轻量级的Java持久层框架,它与Hibernate和JPA等ORM框架不同,Ibatis 更强调SQL的灵活性,将SQL语句的编写和执行交给了开发者,允许在XML配置文件或者注解中定义SQL语句,从而实现了数据访问逻辑与业务...
首先,Ibatis是一个轻量级的Java ORM(对象关系映射)框架,它的核心理念是将SQL语句与Java代码分离,提供一种XML或注解方式来定义SQL语句,从而简化数据库访问的复杂性。与传统的JDBC相比,Ibatis提供了一种更方便...
Ibatis 是一个轻量级的Java持久层框架,它提供了SQL映射框架,使得开发者能够将SQL语句直接写在配置文件中,从而避免了Java代码与SQL的硬编码,提高了开发效率和代码的可读性。Ibatis 的设计目标是简化数据访问层的...
struts+spring+ibatis
在IT行业中,数据库操作是必不可少的一部分,而Ibatis作为一个轻量级的持久层框架,为开发者提供了方便快捷的SQL映射工具,使得CRUD(创建、读取、更新、删除)操作变得更加简单易行。相较于Hibernate这样的ORM框架...
Ibatis提供了日志框架的接口,可以通过配置选择合适的日志实现(如Log4j、SLF4J等),以便追踪SQL执行情况。对于运行时异常,Ibatis通常会抛出SQLException,需要捕获并处理。 7. **性能优化**: Ibatis允许缓存...
**Ibatis 框架原理实现** Ibatis 是一个优秀的持久层框架,它允许开发者将SQL语句直接写在XML配置文件中,从而避免了Java代码与SQL的耦合,提高了开发效率。在这个自己编写的Ibatis框架实现中,我们可以看到类似的...