mybatis select 获取序列不递增_【技术在线】DM7 与 mybatis(二)——ID 生成

本文介绍了如何在DM7数据库中利用MyBatis进行ID生成,包括读取序列值、直接插入序列表达式、使用SelectKey和GeneratedKeys返回自增列值的方法,详细解析了XML映射文件和Mapper接口的配置及调用代码。
摘要由CSDN通过智能技术生成

963192d4928fcf15923943e72a715e12.gif

在《DM7与mybatis(一)——基本CRUD》中,我们介绍了dm7与mybatis的环境集成和基本配置,实现基本的CRUD操作。

在应用开发过程中,ID生成是一种常见的需求,通常基于数据库的自增列(如sqlserver、mysql)、序列(如Oracle)来自动生成。DM7同时支持自增列、序列,本文将介绍如何利用DM7和mybatis实现ID自动生成。

环境准备参见《DM7与mybatis(一)——基本CRUD》。

一、读取序列值生成ID

      1、创建示例表和序列

-- 以test用户登录执行以下脚本

-- user_id序列

CREATESEQUENCE seq_user_id

  INCREMENTBY 1 STARTWITH 1

  MAXVALUE 2147483647;

-- 用户信息表

CREATETABLE t_user_seq

(

    id   INTNOTNULL,--用户标识

    name   VARCHAR(20)NOTNULL,--姓名

    phone VARCHAR(50),-- 手机

    email VARCHAR(50),-- 邮箱

    PRIMARYKEY(id)

);

2、pojo对象

由于表t_user_seq和(一)当中表t_user的字段相同,我们可以复用原来的User对象以及对应的alias定义。

package  org.dmstudy.mybatis.domain;

publicclass User {

    private Integer id;

    private String name;

    private String phone;

    private String email;

   //getter/setter省略

}

3、XML映射文件

在resources\mybatis-config.xml中,新增一个mapper配置,加载IdMapper.xml。

     ……

    <mappers>

        <mapperresource="org/dmstudy/mybatis/crud/dao/UserMapper.xml"/>

        <mapperresource="org/dmstudy/mybatis/id/dao/IdMapper.xml"/>

    mappers>

     ……

新增 org/dmstudy/mybatis/id/dao/IdMapper.xml文件,其内容如下:

xmlversion="1.0"encoding="UTF-8"?>

DOCTYPEmapper

  PUBLIC"-//mybatis.org//DTD  Mapper 3.0//EN"

  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mappernamespace="org.dmstudy.mybatis.id.dao.IdMapper">

    <selectid="getNextUserId"resultType="int">

        select seq_user_id.nextval  from dual

    select>

    <insertid="insert"parameterType="User">

        insert into t_user_seq

        (id,name,phone,email)

        values

        (#{id},#{name},#{phone},#{email})

    insert> 

mapper>

注意namespace值对应为"org.dmstudy.mybatis.id.dao.IdMapper"

其中id=getNextUserId的SELECT节点配置的sql语句是从序列seq_user_id中获取下一个序列值,该值根据定义从1开始,每次增量为1。

id=insert的INSERT节点配置了向表t_user_seq插入记录的语句。

4、Mapper接口

创建org.dmstudy.mybatis.id.dao.IdMapper.java文件,内容如下:

package  org.dmstudy.mybatis.id.dao;

import  org.dmstudy.mybatis.domain.User;

publicinterface IdMapper  {

    int  getNextUserId();

    int insert(User  user);

}

注意接口的全名org.dmstudy.mybatis.id.dao.IdMapper、接口方法getNextUserId、insert与IdMapper.xml中的namespace、语句映射节点id保持一致。

5、调用代码

package  org.dmstudy.mybatis.id;

……

publicclass IdApp {

    ……

    publicvoid insert() {

        System.out.println("---  insert  ---");

        // 新建user对象,注意未设置id值

        User user = new User();

        user.setName("dmtech");

        user.setPhone("400-6489899");

        user.setEmail("dmtech@dameng.com");

        SqlSession sqlSession = sqlSessionFactory.openSession();

        try {

             // 获取mapper对象

             IdMapper mapper = sqlSession.getMapper(IdMapper.class);

             // 获取id值

             Integer id = mapper.getNextUserId();

             System.out.println("成功获取seq_user_id的nextval: " + id);

             // 设置id值

             user.setId(id);

             // 将user插入数据库

             intcnt = mapper.insert(user);

             sqlSession.commit();

             System.out.println("成功插入 " + cnt + "条记录! ");

        } catch (Exception e) {

             System.out.println("insert执行失败 ,原因:" + e.getMessage());

             e.printStackTrace();

             sqlSession.rollback();

        } finally {

             sqlSession.close();

        }

    }

}

查看执行过程输出log4j日志信息

---insert ---

DEBUG [main] - Opening JDBC Connection

DEBUG [main] - Created connection 288994035.

DEBUG [main] - Setting autocommit to false on JDBC  Connection [dm.jdbc.driver.DmdbConnection@1139b2f3]

DEBUG [main] - ==>   Preparing: select seq_user_id.nextval from dual

DEBUG [main] - ==> Parameters:

DEBUG [main] - <==      Total: 1

成功获取序列seq_user_id的nextval: 40

DEBUG [main] - ==>   Preparing: insert into t_user_seq (id,name,phone,email) values  (?,?,?,?)

DEBUG [main] - ==> Parameters: 40(Integer),  dmtech(String), 400-6489899(String), dmtech@dameng.com(String)

DEBUG [main] - <==     Updates: 1

DEBUG [main] - Committing JDBC Connection  [dm.jdbc.driver.DmdbConnection@1139b2f3]

成功插入 1条记录!

DEBUG [main] - Resetting autocommit to true on JDBC  Connection [dm.jdbc.driver.DmdbConnection@1139b2f3]

DEBUG [main] - Closing JDBC Connection  [dm.jdbc.driver.DmdbConnection@1139b2f3]

DEBUG [main] - Returned connection 288994035 to pool.

当执行Integer id = mapper.getNextUserId()时,mybatis底层实际执行语句” selectseq_user_id.nextval from dual”,将返回值40(该值每次运行都会递增)作为ID值赋值给user参数,并插入到数据库表t_user_seq中。

二、直接插入序列表达式

1、XML映射文件

IdMapper.xml文件中,新增一个语句映射节点“insertSeqExpr“,其内容如下:

<mappernamespace="org.dmstudy.mybatis.id.dao.IdMapper">

    ……

    <insertid="insertSeqExpr"parameterType="User">

        insert  into t_user_seq

        (id,name,phone,email)

        values

        (seq_user_id.nextval,#{name},#{phone},#{email})

    insert>

mapper>

2、Mapper接口

在IdMapper接口中,添加相应方法,内容如下:

package  org.dmstudy.mybatis.id.dao;

import  org.dmstudy.mybatis.domain.User;

publicinterface IdMapper  {

    ……

    //直接用序列表达式作为id值插入

    int  insertSeqExpr(User user);

}

3、调用代码

package  org.dmstudy.mybatis.id;

……

publicclass IdApp {

……

    publicvoid insertSeqExpr() {

        System.out.println("---  insertSeqExpr  ---");

        // 新建user对象,不设置id值

        User user = new User();

        user.setName("dmtech");

        user.setPhone("400-6489899");

        user.setEmail("dmtech@dameng.com");

        SqlSession sqlSession = sqlSessionFactory.openSession();

        try {

             // 获取mapper对象

             IdMapper mapper = sqlSession.getMapper(IdMapper.class);

             // 将user插入数据库

             intcnt = mapper.insertSeqExpr(user);

             sqlSession.commit();

             System.out.println("成功插入 " + cnt + "条记录! ");

             if (user.getId() == null) {

                 System.out.println("无法获取插入后的id值: " + user.getId());

             } else {

                 System.out.println("成功获取插入后的id值: " + user.getId());

             }

        } catch (Exception e) {

             System.out.println("insertSeqExpr执行失败 ,原因:" + e.getMessage());

             e.printStackTrace();

             sqlSession.rollback();

        } finally {

             sqlSession.close();

        }

}

}

查看执行过程输出log4j日志信息

---insertSeqExpr ---

DEBUG  [main] - Opening JDBC Connection

DEBUG  [main] - Checked out connection 288994035 from pool.

DEBUG  [main] - Setting autocommit to false on JDBC Connection  [dm.jdbc.driver.DmdbConnection@1139b2f3]

DEBUG  [main] - ==>  Preparing: insert into t_user_seq  (id,name,phone,email) values (seq_user_id.nextval,?,?,?)

DEBUG  [main] - ==> Parameters: dmtech(String), 400-6489899(String), dmtech@dameng.com(String)

DEBUG  [main] - <==    Updates: 1

DEBUG  [main] - Committing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3]

成功插入 1条记录!

无法获取插入后的id值: null

DEBUG  [main] - Resetting autocommit to true on JDBC Connection  [dm.jdbc.driver.DmdbConnection@1139b2f3]

DEBUG  [main] - Closing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3]

DEBUG [main]  - Returned connection 288994035 to pool.

注意该方法执行时,只有name、phone、email列是用输入参数user的属性值设置,而id列则直接使用表达式 seq_user_id.nextval 作为值。

在插入成功后,利用DM7管理工具可以在数据库中查看t_user_seq可以发现已经新增了记录并且id值也生成了。对于输入参数user对象,我们试图访问user的id属性,发现仍然是null。

相对于上一种方法,本方法只需定义一个节点和一个接口方法,程序相对简单。但本方法最大的不足在于id值是在数据库中执行sql语句时产生,我们没法马上知道该值具体是多少,对于不怎么关心ID值的场景(如插入新日志记录)问题不大,对于有些业务场景必须马上获取新增记录的ID(如新增记录ID需要传入到下一流程,主表记录ID需要作为字表记录外键等)则不合适。

三、使用SelectKey返回序列值

1、XML映射文件

Mybatis提供了标签,可以帮助用户在获取ID值后,一方面作为作为sql执行的参数,同时还会把ID值反写到输入对象参数中。

IdMapper.xml文件中,新增一个语句映射节点“insertSequence“,其内容如下:

<mappernamespace="org.dmstudy.mybatis.id.dao.IdMapper">

    ……

    <insertid="insertSequence"parameterType="User">

        <selectKeyresultType="int"keyProperty="id"order="BEFORE">

           select  seq_user_id.nextval from dual

        selectKey>

        insert  into t_user_seq

        (id,name,phone,email)

        values

        (#{id},#{name},#{phone},#{email})

    insert>

mapper>

注意selectKey中的sql语句用来获取ID值,order="BEFORE"表示该语句会在主体的insert语句之前执行。

2、Mapper接口

在IdMapper接口中,添加相应方法,内容如下:

package org.dmstudy.mybatis.id.dao;

import  org.dmstudy.mybatis.domain.User;

publicinterface IdMapper {

     ……

    //使用序列插入id

    int insertSequence(User user);

}

3、调用代码

package  org.dmstudy.mybatis.id;

……

publicclass IdApp {

……

    publicvoid insertSequence() {

        System.out.println("---  insertSequence  ---");

        // 新建user对象,不设置id值

        User user = new User();

        user.setName("dmtech");

        user.setPhone("400-6489899");

        user.setEmail("dmtech@dameng.com");

        SqlSession sqlSession = sqlSessionFactory.openSession();

        try {

             // 获取mapper对象

             IdMapper mapper = sqlSession.getMapper(IdMapper.class);

             // 将user插入数据库

             intcnt = mapper.insertSequence(user);

             sqlSession.commit();

             System.out.println("成功插入 " + cnt + "条记录! ");

             if (user.getId() == null) {

                 System.out.println("无法获取插入后的id值: " + user.getId());

             } else {

                 System.out.println("成功获取插入后的id值: " + user.getId());

             }

        } catch (Exception e) {

             System.out.println("insertSequence执行失败 ,原因:" + e.getMessage());

             e.printStackTrace();

             sqlSession.rollback();

        } finally {

             sqlSession.close();

        }

}

}

查看执行过程输出log4j日志信息

---insertSequence ---

DEBUG  [main] - Opening JDBC Connection

DEBUG  [main] - Checked out connection 288994035 from pool.

DEBUG  [main] - Setting autocommit to false on JDBC Connection  [dm.jdbc.driver.DmdbConnection@1139b2f3]

DEBUG  [main] - ==>  Preparing: select seq_user_id.nextval from dual  

DEBUG  [main] - ==> Parameters:

DEBUG  [main] - <==      Total: 1

DEBUG  [main] - ==>  Preparing: insert into t_user_seq  (id,name,phone,email) values (?,?,?,?)

DEBUG  [main] - ==> Parameters: 42(Integer),  dmtech(String), 400-6489899(String), dmtech@dameng.com(String)

DEBUG  [main] - <==    Updates: 1

DEBUG  [main] - Committing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3]

成功插入 1条记录!

成功获取插入后的id值: 42

DEBUG  [main] - Resetting autocommit to true on JDBC Connection  [dm.jdbc.driver.DmdbConnection@1139b2f3]

DEBUG  [main] - Closing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3]

DEBUG [main]  - Returned connection 288994035 to pool.

从调用代码看,跟方法二直接插入序列表达式的调用代码一样。从实际执行情况看,本方法首先执行了中定义的语句,并将其返回值42作为id的参数,执行主体的sql语句。

执行成功后,我们试图获取输入参数user对象的id属性,发现其值已经被设置为42,即刚刚生成的ID值。

四、使用SelectKey返回自增列值

    DM7不仅支持序列,也支持自增列,对原来习惯mysql、sqlserver的用户,可以参考下面的方法。

1、创建示例表

以test用户登录,执行以下脚本:

-- 以test用户登录执行脚本

-- 以test用户登录执行

-- 用户信息表

CREATETABLE t_user_ident

(

    id   INTIDENTITY(1,1)NOTNULL,--用户标识

    name   VARCHAR(20)NOTNULL,--姓名

    phone VARCHAR(50),-- 手机

    email VARCHAR(50),-- 邮箱

    PRIMARYKEY(id)

);

创建表t_user_ident,其中id列使用了自增列,从1开始,每次增量为1。

2、XML映射文件

IdMapper.xml文件中,新增一个语句映射节点“insertIdentity“,其内容如下:

<mappernamespace="org.dmstudy.mybatis.id.dao.IdMapper">

    ……

    <insertid="insertIdentity"parameterType="User">

        <selectKeyresultType="int"keyProperty="id"order="AFTER">

           select @@identity

        selectKey>

        insert into t_user_ident

        (name,phone,email)

        values

        (#{name},#{phone},#{email})

    insert>

mapper>

order=" AFTER "表示该语句会在主体的insert语句之后执行,而select @@identity语句则是返回刚刚插入的自增列的值。

2、Mapper接口

在IdMapper接口中,添加相应方法,内容如下:

package  org.dmstudy.mybatis.id.dao;

import  org.dmstudy.mybatis.domain.User;

publicinterface IdMapper {

     ……

    //使用自增列插入id

    int  insertIdentity(User user);

}

3、调用代码

package  org.dmstudy.mybatis.id;

……

publicclass IdApp {

……

    publicvoid insertIdentity() {

        System.out.println("---  insertIdentity  ---");

        // 新建user对象,不设置id值

        User user = new User();

        user.setName("dmtech");

        user.setPhone("400-6489899");

        user.setEmail("dmtech@dameng.com");

        SqlSession sqlSession = sqlSessionFactory.openSession();

        try {

             // 获取mapper对象

             IdMapper mapper = sqlSession.getMapper(IdMapper.class);

             // 将user插入数据库

             intcnt = mapper.insertIdentity(user);

             sqlSession.commit();

             System.out.println("成功插入 " + cnt + "条记录! ");

             if (user.getId() == null) {

                 System.out.println("无法获取插入后的id值: " + user.getId());

             } else {

                 System.out.println("成功获取插入后的id值: " + user.getId());

             }

        } catch (Exception e) {

             System.out.println("insertIdentity执行失败 ,原因:" + e.getMessage());

             e.printStackTrace();

             sqlSession.rollback();

        } finally {

             sqlSession.close();

        }

    } }

查看执行过程输出log4j日志信息

---insertIdentity ---

DEBUG  [main] - Opening JDBC Connection

DEBUG  [main] - Checked out connection 288994035 from pool.

DEBUG  [main] - Setting autocommit to false on JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3]

DEBUG  [main] - ==>  Preparing: insert into t_user_ident  (name,phone,email) values (?,?,?)

DEBUG  [main] - ==> Parameters: dmtech(String), 400-6489899(String), dmtech@dameng.com(String)

DEBUG  [main] - <==    Updates: 1

DEBUG  [main] - ==>  Preparing: select  @@identity

DEBUG  [main] - ==> Parameters:

DEBUG  [main] - <==      Total: 1

DEBUG  [main] - Committing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3]

成功插入 1条记录!

成功获取插入后的id值: 25

DEBUG  [main] - Resetting autocommit to true on JDBC Connection  [dm.jdbc.driver.DmdbConnection@1139b2f3]

DEBUG  [main] - Closing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3]

DEBUG [main]  - Returned connection 288994035 to pool.

从调用代码看,跟前面两种方法的调用代码一样,但底层sql实际执行情况不一样。本方法首先执行的是主体中的insert语句,而且id列也没有出现在insert列中,是由数据库自增列来产生值。随后执行了中定义的语句。最后检查输入参数user对象的id属性,发现其值也已经被设置,其值25跟数据库中刚插入的记录一致。

五、使用GeneratedKeys返回自增列值

    对于刚刚插入的自增列的值,除了使用select@@identity 返回,还可以利用jdbc提供的RETURN_GENERATED_KEYS选项来获取,mybatis支持该方法。

1、XML映射文件

IdMapper.xml文件中,新增一个语句映射节点“insertUseGeneratedKeys“,其内容如下:

<mappernamespace="org.dmstudy.mybatis.id.dao.IdMapper">

    ……

    <insertid="insertUseGeneratedKeys"  parameterType="User"useGeneratedKeys="true"keyProperty="id">

        insert into t_user_ident

        (name,phone,email)

        values

        (#{name},#{phone},#{email})

    insert> 

mapper>

useGeneratedKeys="true"表示mybatis执行该语句时,会在创建PreparedStatement对象时添加PreparedStatement.RETURN_GENERATED_KEYS标记,这样jdbc驱动会在执行成功后额外返回一个结果集,其中包含了服务器端刚生成的ID值。

2、Mapper接口

在IdMapper接口中,添加相应方法,内容如下:

package  org.dmstudy.mybatis.id.dao;

import  org.dmstudy.mybatis.domain.User;

publicinterface IdMapper {

     ……

    int insertUseGeneratedKeys(User  user);

}

3、调用代码

package  org.dmstudy.mybatis.id;

……

publicclass IdApp {

……

    publicvoid insertUseGeneratedKeys() {

        System.out.println("---  insertUseGeneratedKeys  ---");

        // 新建user对象,不设置id值

        User user = new User();

        user.setName("dmtech");

        user.setPhone("400-6489899");

        user.setEmail("dmtech@dameng.com");

        SqlSession sqlSession = sqlSessionFactory.openSession();

        try {

             // 获取mapper对象

             IdMapper mapper = sqlSession.getMapper(IdMapper.class);

             // 将user插入数据库

             intcnt = mapper.insertUseGeneratedKeys(user);

             sqlSession.commit();

             System.out.println("成功插入 " + cnt + "条记录! ");

             if (user.getId() == null) {

                 System.out.println("无法获取插入后的id值: " + user.getId());

             } else {

                 System.out.println("成功获取插入后的id值: " + user.getId());

             }

        } catch (Exception e) {

             System.out.println("insertUseGeneratedKeys执行失败 ,原因:" + e.getMessage());

             e.printStackTrace();

             sqlSession.rollback();

        } finally {

             sqlSession.close();

        }

    }  

}

查看执行过程输出log4j日志信息

---insertUseGeneratedKeys ---

DEBUG  [main] - Opening JDBC Connection

DEBUG  [main] - Checked out connection 288994035 from pool.

DEBUG  [main] - Setting autocommit to false on JDBC Connection  [dm.jdbc.driver.DmdbConnection@1139b2f3]

DEBUG  [main] - ==>  Preparing: insert into t_user_ident  (name,phone,email) values (?,?,?)

DEBUG  [main] - ==> Parameters: dmtech(String), 400-6489899(String), dmtech@dameng.com(String)

DEBUG  [main] - <==    Updates: 1

DEBUG  [main] - Committing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3]

成功插入 1条记录!

成功获取插入后的id值: 26

DEBUG  [main] - Resetting autocommit to true on JDBC Connection  [dm.jdbc.driver.DmdbConnection@1139b2f3]

DEBUG  [main] - Closing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3]

DEBUG [main]  - Returned connection 288994035 to pool.

从调用代码看,跟前面几种方法的调用代码一样,底层执行的sql语句只有主体中的insert语句,而最后检查输入参数user对象的id属性,发现其值也已经被正确设置,其值26跟数据库中刚插入的记录一致。

cecbd5fe18fe915f1c8495186c5a2747.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值