碰到一个问题:
org.hibernate.id.IdentifierGeneratorHelper类里面的方法:
value:当前值,
factor:model类定义的allocationSize = 100小1,及时99(第一次传入的信息)
public IntegralDataTypeHolder multiplyBy(long factor) { checkInitialized(); value *= factor; return this; },从这里可以看到启动服务器的时候第一次执行到这里,就发现表的主键是tb_generator(保存主键信息)表的gen_value的allocationSize倍数。那么会浪费掉很多主键值。
上面的方法被org.hibernate.id.enhanced.OptimizerFactory的public synchronized Serializable generate()调用,maxLo同时初始化这个变量,这个变量maxLo+1就是factor。
hibernate中自定义主键生成器: http://panyongzheng.iteye.com/blog/1827786
探索 Hibernate 新 TableGenerator 机制 http://www.ibm.com/developerworks/cn/java/j-lo-tablegenerator/index.html?ca=drs-
探索 Hibernate 新 TableGenerator 机制 http://www.itpub.net/thread-1822509-1-1.html
Hibernate的主键生成策略与并发测试 http://blog.sina.com.cn/s/blog_56d8ea900100xb8h.html
一些重要的知识,可以在这里看到.
SpringMVC3.x, Hiberante4, sql server 2008, 数据库的VM内存2G, 本机的web环境内存8G(VM在本机上建立的), j2ee环境option内存:1G. 服务器:jetty, idea采用非调试启动.
这里不想讨论为什么使用@TableGenerator, 因为没必要,只是比较性能而已.
在运行是, 没有手动session.flush()等操作.
使用自定义主键生成器的service
pojo的主键定义示例:
@GeneratedValue(strategy = GenerationType.TABLE,generator="customer_gen") @TableGenerator(name = "customer_gen", table="tb_generator", pkColumnName="gen_name", valueColumnName="gen_value", pkColumnValue="testtable_PK" )
注意,没有设定allocationSize属性,默认是50.
@Override public void saveTestData(int sum) { /* DELETE FROM dbo.testtable3; DELETE FROM dbo.testtable2; DELETE FROM dbo.testtable1; DELETE FROM dbo.testtable; */ Date d1 = new Date(); //单表 for(int i=0; i<sum; i++){ Testtable t = new Testtable(); t.setCode("Test"+i); testtableDao.save(t); //System.out.println("自定义主键生成 记录:"+i+" 单表:"+(new Date()).toString()); } System.out.println("完成单表操作"); //关联 for(int i=0; i<sum; i++){ Testtable1 p = new Testtable1(); p.setCode("P"+i); p = testtable1Dao.save(p); Testtable2 c = new Testtable2(); c.setTesttable1(p); c.setCode("C"+i); testtable2Dao.save(c); //System.out.println("自定义主键生成 记录:"+i+" 关联:"+(new Date()).toString()); } System.out.println("完成关联操作"); //映射 for(int i=0;i<sum; i++){ Testtable t = new Testtable(); t.setCode("T"+i); t = testtableDao.save(t); Testtable2 c = new Testtable2(); c.setCode("C"+i); c = testtable2Dao.save(c); Testtable3 m = new Testtable3(); m.setCode("M"+i); m.setTesttable(t); m.setTesttable2(c); m = testtable3Dao.save(m); //System.out.println("自定义主键生成 记录:"+i+" 映射:"+(new Date()).toString()); } System.out.println("完成映射操作"); System.out.println("Over......"); Date d2 = new Date(); long t = d2.getTime() - d1.getTime(); System.out.println("service耗时=" + (t / 1000) + "s"); }
使用数据库自己的主键生成器的service
pojo的主键定义示例:
@GeneratedValue(strategy = GenerationType.AUTO)
@Override public void saveTestData(int sum) { /* DELETE FROM dbo.atabletest3; DELETE FROM dbo.atabletest2; DELETE FROM dbo.atabletest1; DELETE FROM dbo.atabletest; */ Date d1 = new Date(); //单表 for(int i=0; i<sum; i++){ Atabletest t = new Atabletest(); t.setCode("Test"+i); atabletestDao.save(t); //System.out.println("数据库主键生成 记录:"+i+" 单表:"+(new Date()).toString()); } System.out.println("完成单表操作"); //关联 for(int i=0; i<sum; i++){ Atabletest1 p = new Atabletest1(); p.setCode("P"+i); p = atabletest1Dao.save(p); Atabletest2 c = new Atabletest2(); c.setAtabletest1(p); c.setCode("C"+i); atabletest2Dao.save(c); //System.out.println("数据库主键生成 记录:"+i+" 关联:"+(new Date()).toString()); } System.out.println("完成关联操作"); //映射 for(int i=0;i<sum; i++){ Atabletest t = new Atabletest(); t.setCode("T"+i); t = atabletestDao.save(t); Atabletest2 c = new Atabletest2(); c.setCode("C"+i); c = atabletest2Dao.save(c); Atabletest3 m = new Atabletest3(); m.setAtabletest(t); m.setAtabletest2(c); m.setCode("M"+i); m = atabletest3Dao.save(m); //System.out.println("数据库主键生成 记录:"+i+" 映射:"+(new Date()).toString()); } System.out.println("完成映射操作"); System.out.println("Over......"); Date d2 = new Date(); long t = d2.getTime() - d1.getTime(); System.out.println("service耗时=" + (t / 1000) + "s"); }
调用service的controller方法
@RequestMapping("/test") public ModelAndView test(@RequestParam("flag") int flag, @RequestParam("sum") int sum) { if (flag == 1) { Date d1 = new Date(); testtableManager.saveTestData(sum); Date d2 = new Date(); long t = d2.getTime() - d1.getTime(); System.out.println("使用自定义主键生成器"); System.out.println("记录数:"+(sum*6)+" 耗时=" + (t / 1000) + "s"); } else if (flag == 0) { Date d1 = new Date(); atabletestManager.saveTestData(sum); Date d2 = new Date(); long t = d2.getTime() - d1.getTime(); System.out.println("使用数据库主键生成器"); System.out.println("记录数:"+(sum*6)+" 耗时=" + (t / 1000) + "s"); } else { } return null; }
测试结果:
10万级别的,自定义要快一点, .
1万级别的,数据库自己的主键要快一点, .
1000条级别的,自定义要快一点 .
60w条数据:
使用自定义主键生成器:
service耗时=142s 耗时=1195s, service耗时=130s 耗时=1587s
使用数据库主键生成器
service耗时=974s 耗时=1284s, service耗时=971s 耗时=1662s
6w条数据:
使用自定义主键生成器:
service耗时=13s 耗时=94s, service耗时=12s 耗时=92s, service耗时=12s 耗时=104s
使用数据库主键生成器
service耗时=89s 耗时=92s, service耗时=82s 耗时=85s, service耗时=90s 耗时=93s
6000条数据:
使用自定义主键生成器:
service耗时=1s 耗时=10s, service耗时=1s 耗时=10s, service耗时=1s 耗时=11s
使用数据库主键生成器
service耗时=9s 耗时=10s, service耗时=10s 耗时=12s, service耗时=8s 耗时=10s