前面两篇博客我们介绍了MyBatis主键生成器KeyGenerator(一)MyBatis主键生成器Jdbc3KeyGenerator(二),接下来我们介绍SelectKeyGenerator,

如在Oraclee中并不提供自增组件,提供了Sequence主键,我们就需要执行它的Sequence主键,如在mysql中如下配置:

  1. <insert id="save">
  2. <selectKey resultType="int" keyProperty="id" order="BEFORE">
  3. SELECT LAST_INSERT_ID() AS id
  4. </selectKey>
  5. insert into tbl_log (log_type,log_info) values
  6. (#{logType},#{logInfo})
  7. </insert>

其实现原理就是执行selectKey中的sql语句来获得结果,在SelectKeyGenerator的源码实现中就是执行 select last_insert_id() as id这条sql语句,获得结果,并赋值给id,源码实现如下:

  1. /**
  2. * @author Clinton Begin
  3. * @author Jeff Butler
  4. */
  5. public class SelectKeyGenerator implements KeyGenerator {
  6.  
  7. public static final String SELECT_KEY_SUFFIX = "!selectKey";
  8. private boolean executeBefore;
  9. private MappedStatement keyStatement;
  10.  
  11. public SelectKeyGenerator(MappedStatement keyStatement, boolean executeBefore) {
  12. this.executeBefore = executeBefore;
  13. this.keyStatement = keyStatement;
  14. }
  15.  
  16. @Override
  17. public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
  18. if (executeBefore) {
  19. processGeneratedKeys(executor, ms, parameter);
  20. }
  21. }
  22.  
  23. @Override
  24. public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
  25. if (!executeBefore) {
  26. processGeneratedKeys(executor, ms, parameter);
  27. }
  28. }
  29. //执行来获得结果值
  30. private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
  31. try {
  32. if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {
  33. String[] keyProperties = keyStatement.getKeyProperties();
  34. final Configuration configuration = ms.getConfiguration();
  35. final MetaObject metaParam = configuration.newMetaObject(parameter);
  36. if (keyProperties != null) {
  37. // Do not close keyExecutor.
  38. // The transaction will be closed by parent executor.
  39. Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
  40. //执行获得主键的sql语句
  41. List<Object> values = keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
  42. if (values.size() == 0) {
  43. throw new ExecutorException("SelectKey returned no data.");
  44. } else if (values.size() > 1) {
  45. throw new ExecutorException("SelectKey returned more than one value.");
  46. } else {
  47. //执行结果
  48. MetaObject metaResult = configuration.newMetaObject(values.get(0));
  49. //返回参数如果是一个
  50. if (keyProperties.length == 1) {
  51. //判断返回参数使用有get方法
  52. if (metaResult.hasGetter(keyProperties[0])) {
  53. setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));
  54. } else {
  55. // no getter for the property - maybe just a single value object
  56. // so try that
  57. setValue(metaParam, keyProperties[0], values.get(0));
  58. }
  59. } else {
  60. //如果有多个返回参数则需要循环赋值
  61. handleMultipleProperties(keyProperties, metaParam, metaResult);
  62. }
  63. }
  64. }
  65. }
  66. } catch (ExecutorException e) {
  67. throw e;
  68. } catch (Exception e) {
  69. throw new ExecutorException("Error selecting key or setting result to parameter object. Cause: " + e, e);
  70. }
  71. }
  72.  
  73. //如果有多个返回参数则需要循环赋值
  74. private void handleMultipleProperties(String[] keyProperties,
  75. MetaObject metaParam, MetaObject metaResult) {
  76. String[] keyColumns = keyStatement.getKeyColumns();
  77.  
  78. //如果没设置返回参数的值,则使用结果属性的值
  79. if (keyColumns == null || keyColumns.length == 0) {
  80. // no key columns specified, just use the property names
  81. for (int i = 0; i < keyProperties.length; i++) {
  82. setValue(metaParam, keyProperties[i], metaResult.getValue(keyProperties[i]));
  83. }
  84. } else {
  85. if (keyColumns.length != keyProperties.length) {
  86. throw new ExecutorException("If SelectKey has key columns, the number must match the number of key properties.");
  87. }
  88. for (int i = 0; i < keyProperties.length; i++) {
  89. setValue(metaParam, keyProperties[i], metaResult.getValue(keyColumns[i]));
  90. }
  91. }
  92. }
  93.  
  94. //设置返回参数对应的值
  95. private void setValue(MetaObject metaParam, String property, Object value) {
  96. if (metaParam.hasSetter(property)) {
  97. metaParam.setValue(property, value);
  98. } else {
  99. throw new ExecutorException("No setter found for the keyProperty '" + property + "' in " + metaParam.getOriginalObject().getClass().getName() + ".");
  100. }
  101. }
  102. }

MyBatis主键生成器SelectKeyGenerator(三)的更多相关文章

  1. MyBatis主键生成器Jdbc3KeyGenerator(二)

    上一篇博客MyBatis主键生成器KeyGenerator(一)中我们大体介绍了主键生成器的接口及配置等,接下来我们介绍一下KeyGenerator的实现类Jdbc3KeyGenerator Jdbc ...

  2. MyBatis主键生成器KeyGenerator(一)

    Mybatis提供了主键生成器接口KeyGenerator,insert语句默认是不返回记录的主键值,而是返回插入的记录条数:如果业务层需要得到记录的主键时,可以通过配置的方式来完成这个功能 . 由于 ...

  3. 轻量级封装DbUtils&Mybatis之四MyBatis主键

    MyBatis主键 不支持对象列表存储时对自增id字段的赋值(至少包括3.2.6和3.3.0版本),如果id不是采用底层DB自增主键赋值,不必考虑此问题 温馨提示:分布式DB环境下,DB主键一般会采用 ...

  4. 主键生成器效率提升方案|基于雪花算法和Redis控制进程隔离

    背景 主键生成效率用数据库自增效率也是比较高的,为什么要用主键生成器呢?是因为需要insert主表和明细表时,明细表有个字段是主表的主键作为关联.所以就需要先生成主键填好主表明细表的信息后再一次过在一 ...

  5. Hibernate各种主键生成器策略与配置详解(转载)

    http://www.cnblogs.com/kakafra/archive/2012/09/16/2687569.html 1.assigned 主键由外部程序负责生成,在 save() 之前必须指 ...

  6. Hibernate主键生成器

    主键生成器负责生成数据表记录的主键:increment:为long,short或者int类型主键生成唯一标识.只有在没有其他进程往同一张表中插入数据时才能使用.在集群下不能使用! identity:在 ...

  7. MyBatis主键返回

    在使用MyBatis做持久层时,insert语句默认是不返回记录的主键值,而是返回插入的记录条数:如果业务层需要得到记录的主键时,可以通过配置的方式来完成这个功能. 比如在表的关联关系中,将数据插入主 ...

  8. mybatis 主键UUID生成策略

    <insert id="insert" parameterType="com.lsfwpt.lawmis.po.SysUser"> <sele ...

  9. Hibernate中的主键生成器generator

    本文讲述Hibernate的generator属性的意义.Generator属性有7种class,本文简略描述了这7种class的意义和用法. [xhtml] view plaincopy <c ...

随机推荐

  1. Splay讲解

    Splay讲解 Splay是平衡树的一种,是一种二叉搜索树,我们先讲解一下它的核心部分. Splay的核心部分就是splay,可能有些人会说什么鬼?这样讲解是不是太不认真了?两个字回答:不是.第一个S ...

  2. Linux 基本bash命令

    1.查看文件大小.内存大小.cpu信息.硬盘空间 显示当前目录所有文件大小的命令:ls -lht 内存空间.CPU信息.硬盘空间:htop.top(htop详解参考:http://blog.csdn. ...

  3. Unity3D各平台Application.xxxPath的路径

    前几天我们游戏在一个同事的Android手机上启动时无法正常进入,经查发现Application.temporaryCachePath和Application.persistentDataPath返回 ...

  4. Leetcode难度表及解题汇总

    Leetcode难度表及解题汇总 参考网上一份题目难度表,以及本人的解题. Id Question Difficulty Frequency Data Structures Algorithms Bl ...

  5. Android简易实战教程--第三十八话《自定义通知NotifiCation》

    上一篇小案例,完成了一个普通的通知,点击通知启动了一个活动.但是那里的通知没有加入些"靓点",这一篇就给它加入自定义的布局,完成自定义的通知. 应用:比如QQ音乐为例,当点击音乐播 ...

  6. Texlive 更新命令

    设置repository tlmgr repository set http://mirror.hust.edu.cn/CTAN/systems/texlive/tlnet 上面的例子使用的是华中科技 ...

  7. Android艺术开发探索——第二章:IPC机制(下)

    Android艺术开发探索--第二章:IPC机制(下) 我们继续来讲IPC机制,在本篇中你将会学习到 ContentProvider Socket Binder连接池 一.使用ContentProvi ...

  8. 一起聊聊什么是P问题、NP问题、NPC问题

    概念 P问题:如果一个问题可以找到一个能在多项式的时间里解决它的算法,那么这个问题就属于P问题.通常NOI和NOIP不属于P类问题,我们常见到的一些信息奥赛的题目都是P问题. NP问题:可以在多项式的 ...

  9. Python实现数据库一键导出为Excel表格

    依赖 Python2711 xlwt MySQLdb 数据库相关 连接 获取字段信息 获取数据 Excel基础 workbook sheet 案例 封装 封装之后 测试结果 总结 数据库数据导出为ex ...

  10. premake设置静态运行库

    premake设置静态运行库(金庆的专栏)链接protobuf库时,碰到RuntimeLibrary不匹配:1>libprotobufd.lib(int128.obj) : error LNK2 ...