mybatis主鍵自增,關(guān)聯(lián)查詢,動態(tài)sql方式
mybatis 主鍵自增,關(guān)聯(lián)查詢,動態(tài)sql
主鍵自增
selectKey標(biāo)簽(注解)
selectKey標(biāo)簽
<!-- 新增用戶 --> <insert id="insertUser" parameterType="com.mybatis.po.User"> <selectKey keyProperty="userId" order="AFTER" resultType="java.lang.Integer"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO tb_user(user_name,blog_url,remark) VALUES(#{userName},#{blogUrl},#{remark}) </insert>
selectKey注解
@Insert(" insert into table(c1,c2) values (#{c1},#{c2}) ") @SelectKey(resultType = long.class,keyColumn = "id",before = false,statement = "SELECT LAST_INSERT_ID() AS id",keyProperty = "id")
參數(shù)解釋:
- before=false:由于mysql支持自增長主鍵,所以先執(zhí)行插入語句,再獲取自增長主鍵值
- keyColumn:自增長主鍵的字段名
- keyProperty: 實(shí)體類對應(yīng)存放字段,注意數(shù)據(jù)類型和resultType一致
- tatement:實(shí)際執(zhí)行的sql語句
SelectKey返回的值存在實(shí)體類中,線程安全,所以不論插入成功與否id都會安全自增
useGeneratedKeys屬性、keyProperty屬性
xml文件方式
<!-- 新增用戶 --> <insert id="insertUser" useGeneratedKeys="true" keyProperty="userId" parameterType="com.mybatis.po.User"> INSERT INTO tb_user(user_name,blog_url,remark) VALUES(#{userName},#{blogUrl},#{remark}) </insert>
注解方式
@Insert("INSERT INTO tb_user(user_name,blog_url,remark) VALUES(#{userName},#{blogUrl},#{remark}") @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
參數(shù)解釋:
- useGeneratedKeys屬性表示使用自增主鍵
- keyProperty屬性是Java包裝類對象的屬性名
- keyColumn屬性是mysql表中的字段名
非自增主鍵
uuid類型和Oracle的序列主鍵nextval,它們都是在insert之前生成的,其實(shí)就是執(zhí)行了SQL的uuid()方法及nextval()方法,所以SQL映射文件的配置與上面的配置類似,依然使用< selectKey>標(biāo)簽對,但是order屬性被設(shè)置為before(因?yàn)槭窃趇nsert之前執(zhí)行),resultType根據(jù)主鍵實(shí)際類型設(shè)定
UUID配置
<selectKey keyProperty="userId" order="BEFORE" resultType="java.lang.String"> SELECT uuid() </selectKey>
Oracle序列配置
<selectKey keyProperty="userId" order="BEFORE" resultType="java.lang.String"> SELECT 序列名.nextval() FROM DUAL </selectKey>
關(guān)聯(lián)查詢
添加依賴
<dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.34</version> </dependency> </dependencies>
spring: #DataSource數(shù)據(jù)源 datasource: url: jdbc:mysql://localhost:3306/mybatis_test?useSSL=false& username: root password: root driver-class-name: com.mysql.jdbc.Driver #MyBatis配置 mybatis: type-aliases-package: com.mye.hl07mybatis.api.pojo #別名定義 configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #指定 MyBatis 所用日志的具體實(shí)現(xiàn),未指定時將自動查找 map-underscore-to-camel-case: true #開啟自動駝峰命名規(guī)則(camel case)映射 lazy-loading-enabled: true #開啟延時加載開關(guān) aggressive-lazy-loading: false #將積極加載改為消極加載(即按需加載),默認(rèn)值就是false lazy-load-trigger-methods: "" #阻擋不相干的操作觸發(fā),實(shí)現(xiàn)懶加載 cache-enabled: true #打開全局緩存開關(guān)(二級環(huán)境),默認(rèn)值就是true
使用@One注解實(shí)現(xiàn)一對一關(guān)聯(lián)查詢
需求:獲取用戶信息,同時獲取一對多關(guān)聯(lián)的權(quán)限列表
創(chuàng)建實(shí)體類
@Data @AllArgsConstructor @NoArgsConstructor public class UserInfo { private int userId; //用戶編號 private String userAccount; //用戶賬號 private String userPassword; //用戶密碼 private String blogUrl; //博客地址 private String remark; //備注 private IdcardInfo idcardInfo; //身份證信息 } @Data @AllArgsConstructor @NoArgsConstructor public class IdcardInfo { public int id; //身份證ID public int userId; //用戶編號 public String idCardCode; //身份證號碼 }
一對一關(guān)聯(lián)查詢
@Repository @Mapper public interface UserMapper { /** * 獲取用戶信息和身份證信息 * 一對一關(guān)聯(lián)查詢 */ @Select("SELECT * FROM tb_user WHERE user_id = #{userId}") @Results(id = "userAndIdcardResultMap", value = { @Result(property = "userId", column = "user_id", javaType = Integer.class, jdbcType = JdbcType.INTEGER, id = true), @Result(property = "userAccount", column = "user_account",javaType = String.class, jdbcType = JdbcType.VARCHAR), @Result(property = "userPassword", column = "user_password",javaType = String.class, jdbcType = JdbcType.VARCHAR), @Result(property = "blogUrl", column = "blog_url",javaType = String.class, jdbcType = JdbcType.VARCHAR), @Result(property = "remark", column = "remark",javaType = String.class, jdbcType = JdbcType.VARCHAR), @Result(property = "idcardInfo",column = "user_id", one = @One(select = "com.mye.hl07mybatis.api.mapper.UserMapper.getIdcardInfo", fetchType = FetchType.LAZY)) }) UserInfo getUserAndIdcardInfo(@Param("userId")int userId); /** * 根據(jù)用戶ID,獲取身份證信息 */ @Select("SELECT * FROM tb_idcard WHERE user_id = #{userId}") @Results(id = "idcardInfoResultMap", value = { @Result(property = "id", column = "id"), @Result(property = "userId", column = "user_id"), @Result(property = "idCardCode", column = "idCard_code")}) IdcardInfo getIdcardInfo(@Param("userId")int userId); }
使用@Many注解實(shí)現(xiàn)一對多關(guān)聯(lián)查詢
需求:獲取用戶信息,同時獲取一對多關(guān)聯(lián)的權(quán)限列表
創(chuàng)建實(shí)體類
@Data @AllArgsConstructor @NoArgsConstructor public class RoleInfo { private int id; //權(quán)限ID private int userId; //用戶編號 private String roleName; //權(quán)限名稱 } @Data @AllArgsConstructor @NoArgsConstructor public class UserInfo { private int userId; //用戶編號 private String userAccount; //用戶賬號 private String userPassword; //用戶密碼 private String blogUrl; //博客地址 private String remark; //備注 private IdcardInfo idcardInfo; //身份證信息 private List<RoleInfo> roleInfoList; //權(quán)限列表 }
一對多關(guān)聯(lián)查詢
/** * 獲取用戶信息和權(quán)限列表 * 一對多關(guān)聯(lián)查詢 * @author pan_junbiao */ @Select("SELECT * FROM tb_user WHERE user_id = #{userId}") @Results(id = "userAndRolesResultMap", value = { @Result(property = "userId", column = "user_id", javaType = Integer.class, jdbcType = JdbcType.INTEGER, id = true), @Result(property = "userAccount", column = "user_account",javaType = String.class, jdbcType = JdbcType.VARCHAR), @Result(property = "userPassword", column = "user_password",javaType = String.class, jdbcType = JdbcType.VARCHAR), @Result(property = "blogUrl", column = "blog_url",javaType = String.class, jdbcType = JdbcType.VARCHAR), @Result(property = "remark", column = "remark",javaType = String.class, jdbcType = JdbcType.VARCHAR), @Result(property = "roleInfoList",column = "user_id", many = @Many(select = "com.pjb.mapper.UserMapper.getRoleList", fetchType = FetchType.LAZY)) }) public UserInfo getUserAndRolesInfo(@Param("userId")int userId); /** * 根據(jù)用戶ID,獲取權(quán)限列表 * @author pan_junbiao */ @Select("SELECT * FROM tb_role WHERE user_id = #{userId}") @Results(id = "roleInfoResultMap", value = { @Result(property = "id", column = "id"), @Result(property = "userId", column = "user_id"), @Result(property = "roleName", column = "role_name")}) public List<RoleInfo> getRoleList(@Param("userId")int userId);
MyBatis動態(tài)SQL
script
注解版下,使用動態(tài)SQL需要將sql語句包含在script標(biāo)簽里。
在 < script>< /script>內(nèi)使用特殊符號,則使用java的轉(zhuǎn)義字符,如 雙引號 ""
使用\"\"
代替
<script></script>
< where>標(biāo)簽、< if>標(biāo)簽
if
:通過判斷動態(tài)拼接sql語句,一般用于判斷查詢條件
當(dāng)查詢語句的查詢條件由于輸入?yún)?shù)的不同而無法確切定義時,可以使用< where>標(biāo)簽對來包裹需要動態(tài)指定的SQL查詢條件,而在< where>標(biāo)簽對中,可以使用< if test=“…”>條件來分情況設(shè)置SQL查詢條件
當(dāng)使用標(biāo)簽對包裹 if 條件語句時,將會忽略查詢條件中的第一個and或or
<!-- 查詢用戶信息 --> <select id="queryUserInfo" parameterType="com.mybatis.po.UserParam" resultType="com.mybatis.po.User"> SELECT * FROM tb_user <where> <if test="userId > 0"> and user_id = #{userId} </if> <if test="userName!= null and userName!=''"> and user_name like '%${userName}%' </if> <if test="sex!=null and sex!=''"> and sex = #{sex} </if> </where> </select>
@Select({"<script>" + " select * from tb_user " + "<where>" + "<if test = 'userId != null and userId !=\"\" '> " + "and user_Id = #{userId} " + "</if>" + "<if test = 'userPassword != null and userPassword !=\"\" '> " + "and user_password like CONCAT('%',#{userPassword},'%')" + "</if>" + "</where>" + "</script>"})
< sql>片段
MyBatis提供了可以將復(fù)用性比較強(qiáng)的SQL語句封裝成“SQL片段”,在需要使用該SQL片段的映射配置中聲明一下,即可引入該SQL語句,聲明SQL片段的格式如下:
<sql id="query_user_where"> <!-- 要復(fù)用的SQL語句 --> </sql>
例子:
<!--用戶查詢條件SQL片段--> <sql id="query_user_where"> <if test="userId>0"> AND user_id = #{userId} </if> <if test="userName!=null and userName!=''"> AND user_name like '%${userName}%' </if> <if test="sex!=null and sex!=''"> AND sex = #{sex} </if> </sql> <!-- 查詢用戶信息 --> <select id="queryUserInfo" parameterType="com.mybatis.po.UserParam" resultType="com.mybatis.po.User"> SELECT * FROM tb_user <where> <include refid="query_user_where"/> <!-- 這里可能還會引入其他的SQL片段 --> </where> </select>
id是SQL片段的唯一標(biāo)識,是不可重復(fù)的
SQL片段是支持動態(tài)SQL語句的,但建議,在SQL片段中不要使用< where>標(biāo)簽,而是在調(diào)用的SQL方法中寫< where>標(biāo)簽,因?yàn)樵揝QL方法可能還會引入其他的SQL片段,如果這些多個的SQL片段中都有< where>標(biāo)簽,那么會引起語句沖突。
SQL映射配置還可以引入外部Mapper文件中的SQL片段,只需要在refid屬性填寫的SQL片段的id前添加其所在Mapper文件的namespace信息即可(如:test.query_user_where)
< foreach>標(biāo)簽
< foreach>標(biāo)簽屬性說明:
屬性 | 說明 |
---|---|
index | 當(dāng)?shù)鷮ο笫菙?shù)組,列表時,表示的是當(dāng)前迭代的次數(shù)。 |
item | 當(dāng)?shù)鷮ο笫菙?shù)組,列表時,表示的是當(dāng)前迭代的元素。 |
collection | 當(dāng)前遍歷的對象。 |
open | 遍歷的SQL以什么開頭。 |
close | 遍歷的SQL以什么結(jié)尾。 |
separator | 遍歷完一次后,在末尾添加的字符等。 |
需求:
SELECT * FROM tb_user WHERE user_id=2 OR user_id=4 OR user_id=5; -- 或者 SELECT * FROM tb_user WHERE user_id IN (2,4,5);
案例:
<!-- 使用foreach標(biāo)簽,拼接or語句 --> <sql id="query_user_or"> <if test="ids!=null and ids.length>0"> <foreach collection="ids" item="user_id" open="AND (" close=")" separator="OR"> user_id=#{user_id} </foreach> </if> </sql> <!-- 使用foreach標(biāo)簽,拼接in語句 --> <sql id="query_user_in"> <if test="ids!=null and ids.length>0"> AND user_id IN <foreach collection="ids" item="user_id" open="(" close=")" separator=","> #{user_id} </foreach> </if> </sql>
@Insert("<script>" + "insert into tb_user(user_id,user_account,user_password,blog_url,blog_remark) values" + "<foreach collection = 'list' item = 'item' index='index' separator=','>" + "(#{item.userId},#{item.userAccount},#{item.userPassword},#{item.blogUrl},#{item.blogRemark})" + "</foreach>" + "</script>") int insertByList(@Param("list") List<UserInfo> userInfoList); @Select("<script>" + "select * from tb_user" + " WHERE user_id IN " + "<foreach collection = 'list' item = 'id' index='index' open = '(' separator= ',' close = ')'>" + "#{id}" + "</foreach>" + "</script>") List<UserInfo> selectByList(@Param("list") List<Integer> ids); @Update({"<script>" + "<foreach item='item' collection='list' index='index' open='' close='' separator=';'>" + " UPDATE tb_user " + "<set>" + "<if test='item.userAccount != null'>user_account = #{item.userAccount},</if>" + "<if test='item.userPassword != null'>user_password=#{item.userPassword}</if>" + "</set>" + " WHERE user_id = #{item.userId} " + "</foreach>" + "</script>"}) int updateBatch(@Param("list")List<UserInfo> userInfoList);
< choose>標(biāo)簽、< when>標(biāo)簽、< otherwise>標(biāo)簽
有時我們不想應(yīng)用到所有的條件語句,而只想從中擇其一項(xiàng)。針對這種情況,MyBatis提供了choose元素,它有點(diǎn)像Java中的switch語句。
<select id="queryUserChoose" parameterType="com.mybatis.po.UserParam" resultType="com.mybatis.po.User"> SELECT * FROM tb_user <where> <choose> <when test="userId>0"> AND user_id = #{userId} </when> <when test="userName!=null and userName!=''"> AND user_name like '%${userName}%' </when> <otherwise> AND sex = '女' </otherwise> </choose> </where> </select>
@Select("<script>" + "select * from tb_user " + "<where>" + "<choose>" + "<when test='userId != null and userId != \"\"'>" + " and user_id = #{userId}" + "</when>" + "<otherwise test='userAccount != null and userAccount != \"\"'> " + " and user_account like CONCAT('%', #{userAccount}, '%')" + "</otherwise>" + "</choose>" + "</where>" + "</script>") List<UserInfo> selectAll(UserInfo userInfo);
< trim>標(biāo)簽、< set>標(biāo)簽
MyBatis還提供了< trim>標(biāo)簽,我們可以通過自定義< trim>標(biāo)簽來定制< where>標(biāo)簽的功能。比如,和< where>標(biāo)簽等價的自定義 < trim>標(biāo)
prefixOverrides 屬性會忽略通過管道分隔的文本序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 屬性中的內(nèi)容,并且插入 prefix 屬性中指定的內(nèi)容。
使用自定義< trim>標(biāo)簽來定制< where>標(biāo)簽的功能,獲取用戶信息:
<!-- 查詢用戶信息 --> <select id="queryUserTrim" parameterType="com.mybatis.po.UserParam" resultType="com..mybatis.po.User"> SELECT * FROM tb_user <trim prefix="WHERE" prefixOverrides="AND |OR "> <if test="userId>0"> and user_id = #{userId} </if> <if test="userName!=null and userName!=''"> and user_name like '%${userName}%' </if> <if test="sex!=null and sex!=''"> and sex = #{sex} </if> </trim> </select>
在修改用戶信息的SQL配置方法中,使用< set>標(biāo)簽過濾多余的逗號:
<!-- 修改用戶信息 --> <update id="updateUser" parameterType="com.pjb.mybatis.po.UserParam"> UPDATE tb_user <set> <if test="userName != null">user_name=#{userName},</if> <if test="sex != null">sex=#{sex},</if> <if test="age >0 ">age=#{age},</if> <if test="blogUrl != null">blog_url=#{blogUrl}</if> </set> where user_id = #{userId} </update>
這里,< set>標(biāo)簽會動態(tài)前置SET關(guān)鍵字,同時也會刪掉無關(guān)的逗號,因?yàn)橛昧藯l件語句之后很可能就會在生成的SQL語句的后面留下這些逗號。因?yàn)橛玫氖?ldquo;if”元素,若最后一個“if”沒有匹配上而前面的匹配上,SQL 語句的最后就會有一個逗號遺留。
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
MyBatis處理CLOB/BLOB類型數(shù)據(jù)以及解決讀取問題
這篇文章主要介紹了MyBatis處理CLOB/BLOB類型數(shù)據(jù)以及解決讀取問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-04-04解決SpringBoot ClassPathResource的大坑(FileNotFoundException)
這篇文章主要介紹了解決SpringBoot ClassPathResource的大坑(FileNotFoundException),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06詳解 Java Maximum redirects (100) exceeded
這篇文章主要介紹了詳解 Java Maximum redirects (100) exceeded的相關(guān)資料,需要的朋友可以參考下2017-05-05spring事務(wù)之事務(wù)掛起和事務(wù)恢復(fù)源碼解讀
這篇文章主要介紹了spring事務(wù)之事務(wù)掛起和事務(wù)恢復(fù)源碼解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11Java 異步回調(diào)機(jī)制實(shí)例分析
這篇文章主要介紹了Java 異步回調(diào)機(jī)制實(shí)例解析的相關(guān)資料,需要的朋友可以參考下2017-02-02詳解Springboot如何優(yōu)雅的進(jìn)行數(shù)據(jù)校驗(yàn)
基于?Spring?Boot?,如何“優(yōu)雅”的進(jìn)行數(shù)據(jù)校驗(yàn)?zāi)?,本文將待大家詳?xì)介紹Springboot如何優(yōu)雅的進(jìn)行數(shù)據(jù)校驗(yàn),文中有詳細(xì)的代碼示例和流程步驟,需要的朋友可以參考下2023-06-06MyBatis 中 ${}和 #{}的正確使用方法(千萬不要亂用)
這篇文章主要介紹了MyBatis 中 ${}和 #{}的正確使用方法,本文給大家提到了MyBatis 中 ${}和 #{}的區(qū)別,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07Java運(yùn)用SWT插件編寫桌面記事本應(yīng)用程序
這篇文章主要為大家介紹了一個Java項(xiàng)目實(shí)戰(zhàn),一步步教你實(shí)現(xiàn)記事本,步驟很詳細(xì),運(yùn)用SWT插件手把手編寫記事本,感興趣的小伙伴們可以參考一下2016-01-01