Mybatis3中方法返回生成的主鍵:XML,@SelectKey,@Options詳解
需求
在很多業(yè)務(wù)場(chǎng)景中,我們希望插入一條記錄時(shí)就返回該記錄的相關(guān)信息,返回主鍵顯得尤為重要。
解決方案
1、XML中配置
在定義xml映射器時(shí)設(shè)置屬性u(píng)seGeneratedKeys值為true,并分別指定屬性keyProperty和keyColumn為對(duì)應(yīng)的數(shù)據(jù)庫記錄主鍵字段與Java對(duì)象的主鍵屬性。
key | 釋意 |
---|---|
useGeneratedKeys | 取值范圍true/false(默認(rèn)值),設(shè)置是否使用JDBC的getGenereatedKeys方法獲取主鍵并賦值到keyProperty設(shè)置的領(lǐng)域模型屬性中。MySQL和SQLServer執(zhí)行auto-generated key field,因此當(dāng)數(shù)據(jù)庫設(shè)置好自增長主鍵后,可通過JDBC的getGeneratedKeys方法獲取。但像Oralce等不支持auto-generated key field的數(shù)據(jù)庫就不能用這種方法獲取主鍵了 |
keyProperty | 默認(rèn)值unset,用于設(shè)置getGeneratedKeys方法或selectKey子元素返回值將賦值到領(lǐng)域模型的哪個(gè)屬性中 |
keyColumn | 設(shè)置數(shù)據(jù)表自動(dòng)生成的主鍵名。對(duì)特定數(shù)據(jù)庫(如PostgreSQL),若自動(dòng)生成的主鍵不是第一個(gè)字段則必須設(shè)置 |
自增主鍵
<insert id="insert" parameterType="com.xzbd.User" useGeneratedKeys=”true” keyProperty=”id”> insert into user (username,password,email,bio) values (#{username},#{password},#{email},#{bio}) </insert>
使用標(biāo)簽selectKey
和select LAST_INSERT_ID()
<!-- mysql的自增ID :LAST_INSERT_ID --> <insert id="inserUser2" parameterType="com.xzbd.User" > <selectKey keyProperty="user_id" order="AFTER" resultType="java.lang.Integer"> select LAST_INSERT_ID() </selectKey> insert into t_user(name,age) value(#{name},#{age}) </insert>
非自增,UUID
<insert id="inserUser4" parameterType="com.xzbd.User" > <selectKey keyProperty="user_id" order="AFTER" resultType="java.lang.Integer"> select uuid() </selectKey> insert into t_user(user_id,name,age) value(#{user_id},#{name},#{age}) </insert>
2、Mapper中使用@SelectKey或@Options注解配置
@SelectKey
注解的功能與 <selectKey>
標(biāo)簽完全一致,用在已經(jīng)被@Insert
、@InsertProvider
或 @Update
、@UpdateProvider
注解了的方法上。
在未被上述四個(gè)注解的方法上作 @SelectKey
注解則視為無效。
如果你指定了 @SelectKey
注解,那么 MyBatis
就會(huì)忽略掉由 @Options
注解所設(shè)置的生成主鍵或設(shè)置(configuration)屬性,即@SelectKey
與 @Options
不應(yīng)同時(shí)使用。
@SelectKey
屬性 | 描述 |
---|---|
keyProperty | selectKey 語句結(jié)果應(yīng)該被設(shè)置的目標(biāo)屬性。 |
resultType | 結(jié)果的類型。MyBatis 通??梢运愠鰜?但是寫上也沒有問題。MyBatis 允許任何簡(jiǎn)單類型用作主鍵的類型,包括字符串。 |
order | 這可以被設(shè)置為 BEFORE 或 AFTER。如果設(shè)置為 BEFORE,那么它會(huì)首先選擇主鍵,設(shè)置 keyProperty 然后執(zhí)行插入語句。如果設(shè)置為 AFTER,那么先執(zhí)行插入語句,然后是 selectKey 元素-這和如 Oracle 數(shù)據(jù)庫相似,可以在插入語句中嵌入序列調(diào)用。 |
statementType | 和前面的相 同,MyBatis 支持 STATEMENT ,PREPARED 和CALLABLE 語句的映射類型,分別代表 PreparedStatement 和CallableStatement 類型。 |
示例如下:
@Insert("insert into user (name) values(#{name})") @SelectKey(statement="select LAST_INSERT_ID()", keyProperty="id", before=false, resultType=int.class) int insert(String name);
@Options
該注解能更精細(xì)化的控制SQL執(zhí)行,其代碼如下:
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Options { boolean useCache() default true; boolean flushCache() default false; ResultSetType resultSetType() default ResultSetType.FORWARD_ONLY; StatementType statementType() default StatementType.PREPARED; int fetchSize() default -1; int timeout() default -1; boolean useGeneratedKeys() default false; String keyProperty() default "id"; String keyColumn() default ""; }
示例如下:
@InsertProvider(type = SqlProviderAdapter.class, method = "insert") @SelectKey( keyProperty = "record.id", before = false, resultType = Long.class,statement = {"select last_insert_id()"} ) int insert(InsertStatementProvider<User> insertStatement);
3、特別案例MyBatis Dynamic SQL
官方文檔中Insert Statements描述如下
MyBatis supports returning generated values from a single row insert, or a batch insert. In either case, it is simply a matter of configuring the insert mapper method appropriately. For example, to retrieve the value of a calculated column configure your mapper method like this:
... @InsertProvider(type=SqlProviderAdapter.class, method="insert") @Options(useGeneratedKeys=true, keyProperty="row.fullName") int insert(InsertStatementProvider<GeneratedAlwaysRecord> insertStatement); ...
The important thing is that the keyProperty is set correctly. It should always be in the form row. where is the attribute of the record class that should be updated with the generated value.
注意
keyProperty="row.fullName”
中的row
不一定正確,按照這個(gè)寫后,會(huì)報(bào)錯(cuò)
org.apache.ibatis.executor.ExecutorException: No setter found for the keyProperty 'xxx' in …… DefaultInsertStatementProvider
的異常,改為 keyProperty="fullName“
也會(huì)報(bào)異常,通過查看 DefaultInsertStatementProvider
源碼
最終通過代碼為
keyProperty="rocord.fullName”
4、批量插入
批量插入和單條插入差不多, MyBatis Dynamic SQL
批量插入案例如下。
MyBatis supports returning generated values from a multiple row insert statement with some limitations.
The main limitation is that MyBatis does not support nested lists in parameter objects.
Unfortunately, the MultiRowInsertStatementProvider relies on a nested List.
It is likely this limitation in MyBatis will be removed at some point in the future, so stay tuned.
Nevertheless, you can configure a mapper that will work with the MultiRowInsertStatementProvider as created by this library.
The main idea is to decompose the statement from the parameter map and send them as separate parameters to the MyBatis mapper. For example:
... @InsertProvider(type=SqlProviderAdapter.class, method="insertMultipleWithGeneratedKeys") @Options(useGeneratedKeys=true, keyProperty="records.fullName") int insertMultipleWithGeneratedKeys(String insertStatement, @Param("records") List<GeneratedAlwaysRecord> records); default int insertMultipleWithGeneratedKeys(MultiRowInsertStatementProvider<GeneratedAlwaysRecord> multiInsert) { return insertMultipleWithGeneratedKeys(multiInsert.getInsertStatement(), multiInsert.getRecords()); } ...
The first method above shows the actual MyBatis mapper method.
Note the use of the @Options annotation to specify that we expect generated values.
Further, note that the keyProperty is set to records.fullName - in this case, fullName is a property of the objects in the records List.
The library supplied adapter method will simply return the insertStatement as supplied in the method call.
The adapter method requires that there be one, and only one, String parameter in the method call, and it assumes that this one String parameter is the SQL insert statement.
The parameter can have any name and can be specified in any position in the method’s parameter list.
The @Param annotation is not required for the insert statement. However, it may be specified if you so desire.
The second method above decomposes the MultiRowInsertStatementProvider and calls the first method.
結(jié)論
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- MyBatis insert語句返回主鍵和selectKey標(biāo)簽方式
- mybatis?selectKey賦值未生效的原因分析
- mybatis?獲取更新(update)記錄的id之<selectKey>用法說明
- mybatis的selectKey作用詳解
- Mybatis?selectKey 如何返回新增用戶的id值
- MyBatis如何使用selectKey返回主鍵的值
- Mybatis插入時(shí)返回自增主鍵方式(selectKey和useGeneratedKeys)
- Mybatis @SelectKey用法解讀
- Mybatis示例之SelectKey的應(yīng)用
- MyBatis中selectKey標(biāo)簽及主鍵回填實(shí)現(xiàn)
相關(guān)文章
Java利用Socket實(shí)現(xiàn)網(wǎng)絡(luò)通信功能
在早期的網(wǎng)絡(luò)編程中,Socket是很常見的實(shí)現(xiàn)技術(shù)之一,比如早期的聊天室,就是基于這種技術(shù)進(jìn)行實(shí)現(xiàn)的,另外現(xiàn)在有些消息推送,也可以基于Socket實(shí)現(xiàn),本文小編給大家介紹了Java利用Socket實(shí)現(xiàn)網(wǎng)絡(luò)通信功能的示例,需要的朋友可以參考下2023-11-11淺談java運(yùn)用注解實(shí)現(xiàn)對(duì)類中的方法檢測(cè)的工具
這篇文章主要介紹了淺談java運(yùn)用注解實(shí)現(xiàn)對(duì)類中的方法檢測(cè)的工具,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08Java空格替換逗號(hào)的實(shí)現(xiàn)示例
在編程中,我們經(jīng)常需要對(duì)字符串進(jìn)行各種處理,其中一個(gè)常見的需求是將字符串中的逗號(hào)替換為空格,本文主要介紹了Java空格替換逗號(hào)的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01SpringBoot使用RabbitMQ延時(shí)隊(duì)列(小白必備)
這篇文章主要介紹了SpringBoot使用RabbitMQ延時(shí)隊(duì)列(小白必備),詳細(xì)的介紹延遲隊(duì)列的使用場(chǎng)景及其如何使用,需要的小伙伴可以一起來了解一下2019-12-12SpringBoot封裝JDBC的實(shí)現(xiàn)步驟
本文主要介紹了SpringBoot封裝JDBC的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12springboot中使用Hibernate-Validation校驗(yàn)參數(shù)詳解
這篇文章主要為大家介紹了springboot中使用Hibernate-Validation校驗(yàn)參數(shù)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07