MYSQL, mybatis 如何使用自增主键

通常我们在应用中对mysql执行了insert操作后,需要获取插入记录的自增主键。本文将介绍java环境下的4种方法获取insert后的记录主键auto_increment的值:

  1. 通过JDBC2.0提供的insertRow()方式
  2. 通过JDBC3.0提供的getGeneratedKeys()方式
  3. 通过SQL select LAST_INSERT_ID()函数
  4. 通过SQL @@IDENTITY 变量
  5. mybatis如何操作自增key.

1. 通过JDBC2.0提供的insertRow()方式

自jdbc2.0以来,可以通过下面的方式执行。

Statement stmt = null;
ResultSet rs = null;
try {
    stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,  // 创建Statement
                                java.sql.ResultSet.CONCUR_UPDATABLE);
    stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial");
    stmt.executeUpdate(                                                // 创建demo表
            "CREATE TABLE autoIncTutorial ("
            + "priKey INT NOT NULL AUTO_INCREMENT, "
            + "dataField VARCHAR(64), PRIMARY KEY (priKey))");
    rs = stmt.executeQuery("SELECT priKey, dataField "                 // 检索数据
       + "FROM autoIncTutorial");
    rs.moveToInsertRow();                                              // 移动游标到待插入行(未创建的伪记录)
    rs.updateString("dataField", "AUTO INCREMENT here?");              // 修改内容
    rs.insertRow();                                                    // 插入记录
    rs.last();                                                         // 移动游标到最后一行
    int autoIncKeyFromRS = rs.getInt("priKey");                        // 获取刚插入记录的主键preKey
    rs.close();
    rs = null;
    System.out.println("Key returned for inserted row: "
        + autoIncKeyFromRS);
}  finally {
    // rs,stmt的close()清理
}

 

优点:早期较为通用的做法 

缺点:需要操作ResultSet的游标,代码冗长。

2. 通过JDBC3.0提供的getGeneratedKeys()方式

Statement stmt = null;
ResultSet rs = null;
try {
    stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
                                java.sql.ResultSet.CONCUR_UPDATABLE);  
    // ...
    // 省略若干行(如上例般创建demo表)
    // ...
    stmt.executeUpdate(
            "INSERT INTO autoIncTutorial (dataField) "
            + "values ('Can I Get the Auto Increment Field?')",
            Statement.RETURN_GENERATED_KEYS);                      // 向驱动指明需要自动获取generatedKeys!
    int autoIncKeyFromApi = -1;
    rs = stmt.getGeneratedKeys();                                  // 获取自增主键!
    if (rs.next()) {
        autoIncKeyFromApi = rs.getInt(1);
    }  else {
        // throw an exception from here
    } 
    rs.close();
    rs = null;
    System.out.println("Key returned from getGeneratedKeys():"
        + autoIncKeyFromApi);
}  finally { ... }

 

这种方式只需要2个步骤:

 

1. 在executeUpdate时激活自动获取key;

2.调用Statement的getGeneratedKeys()接口
优点:

1. 操作方便,代码简洁

2. jdbc3.0的标准

3. 效率高,因为没有额外访问数据库

 

这里补充下,

a.在jdbc3.0之前,每个jdbc driver的实现都有自己获取自增主键的接口。在mysql jdbc2.0的driver org.gjt.mm.mysql中,getGeneratedKeys()函数就实现在org.gjt.mm.mysql.jdbc2.Staement.getGeneratedKeys()中。这样直接引用的话,移植性会有很大影响。JDBC3.0通过标准的getGeneratedKeys很好的弥补了这点。

b.关于getGeneratedKeys(),官网还有更详细解释:OracleJdbcGuide

3. 通过SQL select LAST_INSERT_ID()

 

Statement stmt = null;
ResultSet rs = null;
try {
    stmt = conn.createStatement();
    // ...
    // 省略建表
    // ...
    stmt.executeUpdate(
            "INSERT INTO autoIncTutorial (dataField) "
            + "values ('Can I Get the Auto Increment Field?')");
    int autoIncKeyFromFunc = -1;
    rs = stmt.executeQuery("SELECT LAST_INSERT_ID()");             // 通过额外查询获取generatedKey
    if (rs.next()) {
        autoIncKeyFromFunc = rs.getInt(1);
    }  else {
        // throw an exception from here
    } 
    rs.close();
    System.out.println("Key returned from " +
                       "'SELECT LAST_INSERT_ID()': " +
                       autoIncKeyFromFunc);
}  finally {...}

这种方式没什么好说的,就是额外查询一次函数LAST_INSERT_ID().

优点:简单方便

缺点:相对JDBC3.0的getGeneratedKeys(),需要额外多一次数据库查询。

 

补充:

1. 这个函数,在mysql5.5手册的定义是:“returns a BIGINT (64-bit) value representing the first automatically generated value successfully inserted for an AUTO_INCREMENT column as a result of the most recently executed INSERT statement.”。文档点此

2. 这个函数,在connection维度上是“线程安全的”。就是说,每个mysql连接会有个独立保存LAST_INSERT_ID()的结果,并且只会被当前连接最近一次insert操作所更新。也就是2个连接同时执行insert语句时候,分别调用的LAST_INSERT_ID()不会相互覆盖。举个栗子:连接A插入表后LAST_INSERT_ID()返回100,连接B插入表后LAST_INSERT_ID()返回101,但是连接A重复执行LAST_INSERT_ID()的时候,始终返回100,而不是101。这个可以通过监控mysql连接数和执行结果来验证,这里不详述实验过程。

3. 在上面那点的基础上,如果在同一个连接的前提下同时执行insert,那可能2次操作的返回值会相互覆盖。因为LAST_INSERT_ID()的隔离程度是连接级别的。这点,getGeneratedKeys()是可以做的更好,因为getGeneratedKeys()是statement级别的。同个connection的多次statement,getGeneratedKeys()是不会被相互覆盖。

4. 通过SQL SELECT @@IDENTITY

这个方式和LAST_INSERT_ID()效果是一样的。官网文档如此表述:“This variable is a synonym for the last_insert_id variable. It exists for compatibility with other database systems. You can read its value with SELECT @@identity, and set it using SET identity.” 文档点此

 

重要补充:

无论是SELECT LAST_INSERT_ID()还是SELECT @@IDENTITY,对于一条insert语句插入多条记录,永远只会返回第一条插入记录的generatedKey.如:

INSERT INTO t VALUES
    -> (NULL, 'Mary'), (NULL, 'Jane'), (NULL, 'Lisa');
LAST_INSERT_ID(), @@IDENTITY都只会返回'Mary'所在的那条记录的generatedKey

5. 在mybatis里面如何获得自增key?

  例子如下:首先设置 useGeneratedKeys="true",然后指定自增key的id, keyProperty="id"

<!--    public void addEmp(Employee employee);-->
<!--paramterType可以省略
获取自增主键的值:
    mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGeneratedKeys();
    useGeneratedKeys="true";使用自增主键获取主键值策略
    keyPeoperty;指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性
-->
<insert id="addEmp" parameterType="com.mybatis.bean.Employee"
    useGeneratedKeys="true" keyProperty="id">
    insert into tbl_employee(last_name,email,gender)
    values(#{lastName},#{email},#{gender})
</insert>

使用例子:如何得到返回的id 

//测试添加
Employee employee = new Employee(null, "jerry4",null, "1");
mapper.addEmp(employee);
System.out.println(employee.getId());

小结

所以,最好还是通过JDBC3 提供的getGeneratedKeys()函数来获取insert记录的主键。不但简单,而且效率高。

 

在mybatis中,就有相关设置: 

<insert id="save" parameterType="MappedObject" useGeneratedKeys="true" keyProperty="id">
</insert>

可参考mybatis文档:sqlmap-xml

http://blog.youkuaiyun.com/ultrani/article/details/9351573

### 回答1: MyBatis 通过 JDBC API 来操作数据库,而 JDBC API 本身就提供了获取自主键的方法。因此,MyBatis 返回自主键的底层实现方式就是通过 JDBC API 获取自主键。 具体来说,MyBatis 在执行插入操作时,会将生成的 SQL 语句传递给 JDBC 驱动程序。JDBC 驱动程序会执行该 SQL 语句,并返回一个 ResultSet 对象。MyBatis 会通过 ResultSet 对象获取生成的自主键值,并将其设置到对应的实体类或者参数对象中。 下面是一个示例代码,演示了如何在 MyBatis 中返回自主键: ```java public interface UserMapper { // 使用 @Options 注解获取自主键 @Insert("INSERT INTO user (name, age) VALUES (#{name}, #{age})") @Options(useGeneratedKeys = true, keyProperty = "id") int addUser(User user); } ``` 在上面的示例代码中,`@Options` 注解配置了 `useGeneratedKeys` 属性为 `true`,表示使用自动生成的主键。`keyProperty` 属性指定了将自动生成的主键设置到哪个属性中,这里是 `id`。当执行 `addUser` 方法时,MyBatis 会自动获取自主键并设置到 `User` 对象的 `id` 属性中。 ### 回答2: MyBatis返回自主键的底层实现是通过数据库的底层支持来实现的。具体来说,MyBatis会在执行插入操作后获取数据库返回的自主键值,并将其赋值给相应的实体对象或者映射文件中的主键属性。 如果使用MySQL数据库,MyBatis会在插入数据后执行`SELECT LAST_INSERT_ID()`语句,从数据库中获取最近插入的自主键值。然后,MyBatis将返回的自主键值赋值给实体对象或者映射文件中的对应主键属性。 如果使用Oracle数据库,MyBatis会在执行插入操作后,通过调用`Statement.getGeneratedKeys()`方法来获取生成的自主键值。然后,MyBatis将返回的自主键值赋值给实体对象或者映射文件中的对应主键属性。 总之,MyBatis通过底层数据库的支持,使用相应的语句或方法来获取插入操作后的自主键值,并将其赋值给实体对象或者映射文件中的对应属性,以便后续的操作使用。 ### 回答3: MyBatis返回自主键的底层实现是通过数据库的自主键功能来实现的。 在MyBatis中,可以使用数据库相关的插入语句来插入数据,并且使用<selectKey>元素来获取数据库生成的自主键的值。这个元素可以放在insert语句的内部,用于将生成的主键值返回给应用程序。 具体实现步骤如下: 1. 在insert语句中,设置<selectKey>元素,使用keyProperty属性指定将自主键的值存储在哪个属性中。 2. 设置useGeneratedKeys属性为true,表示要使用数据库自动生成的主键值。 3. 设置keyColumn属性,指定数据库自动生成的主键所在的列。 4. 设置order属性,可以指定是在insert语句之前获取自主键值,还是在insert之后获取。 当执行insert语句时,MyBatis会执行相应的数据库操作,获取自动生成的主键值,并将其存储在指定的属性中。随后,可以通过访问该属性来获取自主键的值。 需要注意的是,不同的数据库有不同的自主键实现方式。例如,MySQL使用AUTO_INCREMENT来生成自主键,而Oracle使用序列(Sequence)来实现。MyBatis可以根据不同的数据库类型来自动选择适合的实现方式。 总之,MyBatis返回自主键的底层实现是通过使用数据库的自主键功能实现的,并且在插入语句中使用<selectKey>元素来获取生成的自主键的值。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值