上次用Mybatis仍是2017年作項目的時候,已經好久過去了。中途再沒有用過Mybatis。致使如今學習SpringBoot過程當中遇到一些Mybatis的問題,以此作出總結(XML極簡模式)。固然只是實用方面的總結,具體就不深究 ♂ 了。這裏只總結怎麼用!!!html
(此次直接跳到十一,是由於中間是RabbitMQ 詳解,你們看微笑哥的就夠了)java
源碼:github.com/niaobulashi…mysql
(1)Mybatis是一個半ORM(對象關係映射)框架,它內部封裝了JDBC,開發時只須要關注SQL語句自己,不須要花費精力去處理加載驅動、建立鏈接、建立statement等繁雜的過程。程序員直接編寫原生態sql,能夠嚴格控制sql執行性能,靈活度高。git
(2)MyBatis 可使用 XML 或註解來配置和映射原生信息,將 POJO映射成數據庫中的記錄,避免了幾乎全部的 JDBC 代碼和手動設置參數以及獲取結果集。程序員
(3)經過xml 文件或註解的方式將要執行的各類 statement 配置起來,並經過java對象和 statement中sql的動態參數進行映射生成最終執行的sql語句,最後由mybatis框架執行sql並將結果映射爲java對象並返回。(從執行sql到返回result的過程)。github
(1)基於SQL語句編程,至關靈活,不會對應用程序或者數據庫的現有設計形成任何影響,SQL寫在XML裏,解除sql與程序代碼的耦合,便於統一管理;提供XML標籤,支持編寫動態SQL語句,並可重用。spring
(2)與JDBC相比,減小了50%以上的代碼量,消除了JDBC大量冗餘的代碼,不須要手動開關鏈接;sql
(3)很好的與各類數據庫兼容(由於MyBatis使用JDBC來鏈接數據庫,因此只要JDBC支持的數據庫MyBatis都支持)。數據庫
(4)可以與Spring很好的集成;編程
(5)提供映射標籤,支持對象與數據庫的ORM字段關係映射;提供對象關係映射標籤,支持對象關係組件維護。
(1)SQL語句的編寫工做量較大,尤爲當字段多、關聯表多時,對開發人員編寫SQL語句的功底有必定要求。
(2)SQL語句依賴於數據庫,致使數據庫移植性差,不能隨意更換數據庫。
(1)MyBatis專一於SQL自己,是一個足夠靈活的DAO層解決方案。
(2)對性能的要求很高,或者需求變化較多的項目,如互聯網項目,MyBatis將是不錯的選擇。
(1)Mybatis和hibernate不一樣,它不徹底是一個ORM框架,由於MyBatis須要程序員本身編寫Sql語句。
(2)Mybatis直接編寫原生態sql,能夠嚴格控制sql執行性能,靈活度高,很是適合對關係數據模型要求不高的軟件開發,由於這類軟件需求變化頻繁,一但需求變化要求迅速輸出成果。可是靈活的前提是mybatis沒法作到數據庫無關性,若是須要實現支持多種數據庫的軟件,則須要自定義多套sql映射文件,工做量大。
(3)Hibernate對象/關係映射能力強,數據庫無關性好,對於關係模型要求高的軟件,若是用hibernate開發能夠節省不少代碼,提升效率。
如下的用法實例建議將源碼clone到本地運行,所有使用的是XMl極簡模式
由於我沒有貼出完整的代碼,只貼出關鍵處理的部分
全部測試都已經經過Postman發送請求測試。
不過我建議各位看官能夠用下IDEA的插件:Restfultookit,很是好用的,根據controller定義的url地址快捷生成請求報文,能夠直接測試。對於測試報文來講這個插件簡直無敵!強烈推薦(已經安裝的當我沒說)
任何MySQL數據類型均可以轉換爲Java數據類型。
若是選擇的Java數值數據類型的精度或容量低於要轉換爲的MySQL數據類型,則可能會出現舍入,溢出或精度損失。
下表列出了始終保證有效的轉換。 第一列列出了一種或多種MySQL數據類型,第二列列出了能夠轉換MySQL類型的一種或多種Java類型。
These MySQL Data Types | Can always be converted to these Java types |
---|---|
CHAR, VARCHAR, BLOB, TEXT, ENUM, and SET |
java.lang.String, java.io.InputStream, java.io.Reader, java.sql.Blob, java.sql.Clob |
FLOAT, REAL, DOUBLE PRECISION, NUMERIC, DECIMAL, TINYINT, SMALLINT, MEDIUMINT, INTEGER, BIGINT |
java.lang.String, java.lang.Short, java.lang.Integer, java.lang.Long, java.lang.Double, java.math.BigDecimal |
DATE, TIME, DATETIME, TIMESTAMP |
java.lang.String, java.sql.Date, java.sql.Timestamp |
ResultSet.getObject()方法使用MySQL和Java類型之間的類型轉換,遵循適當的JDBC規範。 ResultSetMetaData.GetColumnTypeName()和ResultSetMetaData.GetColumnClassName()返回的值以下表所示。 有關JDBC類型的更多信息,請參閱java.sql.Types類的參考。
MySQL Type Name | Return value of GetColumnTypeName |
Return value of GetColumnClassName |
---|---|---|
BIT(1) |
BIT |
java.lang.Boolean |
BIT( > 1) |
BIT |
byte[] |
TINYINT |
TINYINT |
java.lang.Boolean if the configuration property tinyInt1isBit is set to true (the default) and the storage size is 1, or java.lang.Integer if not. |
BOOL , BOOLEAN |
TINYINT |
See TINYINT , above as these are aliases for TINYINT(1) , currently. |
SMALLINT[(M)] [UNSIGNED] |
SMALLINT [UNSIGNED] |
java.lang.Integer (regardless of whether it is UNSIGNED or not) |
MEDIUMINT[(M)] [UNSIGNED] |
MEDIUMINT [UNSIGNED] |
java.lang.Integer (regardless of whether it is UNSIGNED or not) |
INT,INTEGER[(M)] [UNSIGNED] |
INTEGER [UNSIGNED] |
java.lang.Integer , if UNSIGNED java.lang.Long |
BIGINT[(M)] [UNSIGNED] |
BIGINT [UNSIGNED] |
java.lang.Long , if UNSIGNED java.math.BigInteger |
FLOAT[(M,D)] |
FLOAT |
java.lang.Float |
DOUBLE[(M,B)] |
DOUBLE |
java.lang.Double |
DECIMAL[(M[,D])] |
DECIMAL |
java.math.BigDecimal |
DATE |
DATE |
java.sql.Date |
DATETIME |
DATETIME |
java.sql.Timestamp |
TIMESTAMP[(M)] |
TIMESTAMP |
java.sql.Timestamp |
TIME |
TIME |
java.sql.Time |
YEAR[(2|4)] |
YEAR |
If yearIsDateType configuration property is set to false , then the returned object type is java.sql.Short . If set to true (the default), then the returned object is of type java.sql.Date with the date set to January 1st, at midnight. |
CHAR(M) |
CHAR |
java.lang.String (unless the character set for the column is BINARY , then byte[] is returned. |
VARCHAR(M) [BINARY] |
VARCHAR |
java.lang.String (unless the character set for the column is BINARY , then byte[] is returned. |
BINARY(M) |
BINARY |
byte[] |
VARBINARY(M) |
VARBINARY |
byte[] |
TINYBLOB |
TINYBLOB |
byte[] |
TINYTEXT |
VARCHAR |
java.lang.String |
BLOB |
BLOB |
byte[] |
TEXT |
VARCHAR |
java.lang.String |
MEDIUMBLOB |
MEDIUMBLOB |
byte[] |
MEDIUMTEXT |
VARCHAR |
java.lang.String |
LONGBLOB |
LONGBLOB |
byte[] |
LONGTEXT |
VARCHAR |
java.lang.String |
ENUM('value1','value2',...) |
CHAR |
java.lang.String |
SET('value1','value2',...) |
CHAR |
java.lang.String |
參考:6.5 Java, JDBC, and MySQL Types
其一:定義字段別名,使之與實體類屬性名一致。
<!-- 查詢用戶信息列表1 -->
<select id="queryUserList1" resultType="com.niaobulashi.entity.SysUser">
SELECT
u.user_id, u.username userNameStr, u.password, u.salt, u.email,
u.mobile, u.status, u.dept_id, u.create_time
FROM
sys_user u
where 1=1
</select>
複製代碼
其二:經過resultMap映射字段名和實體類屬性名保持一致
<resultMap id="sysUserInfoMap" type="com.niaobulashi.entity.SysUser">
<!-- 用戶Id屬性來映射主鍵字段 userId-->
<id property="id" column="userId"/>
<!-- 用result屬性來映射非主鍵字段,property爲實體類屬性名,column爲數據表中的屬性-->
<result property="userNameStr" column="username"/>
</resultMap>
<!--用戶Vo-->
<sql id="selectSysUserVo">
SELECT
u.user_id, u.username, u.password, u.salt,
u.email, u.mobile, u.status, u.dept_id, u.create_time
FROM
sys_user u
</sql>
<!-- 查詢用戶信息列表2 -->
<select id="queryUserList2" resultMap="sysUserInfoMap">
<include refid="selectSysUserVo"/>
where 1=1
</select>
複製代碼
推薦使用第二種。
思路:useGeneratedKeys="true" keyProperty="id"
<!-- 獲取自動生成的(主)鍵值 -->
<insert id="insertSysTest" parameterType="com.niaobulashi.model.SysTest" useGeneratedKeys="true" keyProperty="id">
INSERT INTO sys_test(name, age, nick_name) VALUES (#{name},#{age},#{nickName})
</insert>
複製代碼
獲取自增加主鍵
/** * 獲取自增加主鍵ID * @param sysTest * @throws Exception */
@RequestMapping(value = "/add", method = RequestMethod.POST)
private void addSysTest(@RequestBody SysTest sysTest) throws Exception {
try {
SysTest sysTestParam = new SysTest();
// 將傳入參數Copy到新申明的對象中,這樣才能從sysTestParam中獲取到自增加主鍵
BeanUtils.copyProperties(sysTest, sysTestParam);
this.sysTestService.insertSysTest(sysTestParam);
log.info("獲取自增加主鍵爲:" + sysTestParam.getId());
} catch (Exception e) {
e.printStackTrace();
throw new Exception();
}
}
複製代碼
使用%"#{value}"%"
方法會引發SQL注入
推薦使用:CONCAT('%',#{value},'%')
<!--用戶Vo-->
<sql id="selectSysUserVo">
SELECT
u.user_id, u.username, u.password, u.salt,
u.email, u.mobile, u.status, u.dept_id, u.create_time
FROM
sys_user u
</sql>
<!-- 查詢用戶信息列表2 -->
<select id="queryUserListByName" parameterType="String" resultMap="sysUserInfoMap">
<include refid="selectSysUserVo"/>
where 1=1
and u.username like concat('%',#{userName},'%')
</select>
複製代碼
一、使用@Param
List<SysUser> queryUserByNameAndEmail(@Param("userName") String userName, @Param("email") String email);
複製代碼
<!--使用用戶名和郵箱查詢用戶信息-->
<select id="queryUserByNameAndEmail" resultMap="sysUserInfoMap">
<include refid="selectSysUserVo"/>
<where>
<if test="userName != null and userName != ''">
AND u.username like concat('%',#{userName},'%')
</if>
<if test="email != null and email != ''">
AND u.email like concat('%',#{email},'%')
</if>
</where>
</select>
複製代碼
二、使用JavaBean
這裏給了一些常見的查詢條件:日期、金額。
List<SysUser> queryUserByUser(SysUser sysUser);
複製代碼
<select id="queryUserByUser" parameterType="com.niaobulashi.model.SysUser" resultMap="sysUserInfoMap">
<include refid="selectSysUserVo"/>
<where>
1=1
<if test="userNameStr != null and userNameStr != ''">
AND u.username like concat('%', #{userNameStr}, '%')
</if>
<if test="email != null and email != ''">
AND u.email like concat('%', #{email}, '%')
</if>
<if test="mobile != null and mobile != ''">
AND u.mobile like concat('%', #{mobile}, '%')
</if>
<if test="createDateStart != null and createDateStart != ''">/*開始時間檢索*/
AND date_format(u.create_time, '%y%m%d') <![CDATA[ >= ]]> date_format(#{createDateStart}, '%y%m%d')
</if>
<if test="createDateEnd != null and createDateEnd != ''">/*結束時間檢索*/
AND date_format(u.create_time, '%y%m%d') <![CDATA[ <= ]]> date_format(#{createDateEnd}, '%y%m%d')
</if>
<if test="amtFrom != null and amtFrom != ''">/*起始金額*/
AND u.amt <![CDATA[ >= ]]> #{amtFrom}
</if>
<if test="amtTo != null and amtTo != ''">/*截至金額*/
AND u.amt <![CDATA[ <= ]]> #{amtTo}
</if>
<if test="updateDateStart != null and updateDateStart != ''">/*開始時間檢索*/
AND date_format(u.update_date, '%y%m%d') <![CDATA[ >= ]]> date_format(#{updateDateStart}, '%y%m%d')
</if>
<if test="updateDateEnd != null and updateDateEnd != ''">/*結束時間檢索*/
AND date_format(u.update_date, '%y%m%d') <![CDATA[ <= ]]> date_format(#{updateDateEnd}, '%y%m%d')
</if>
</where>
</select>
複製代碼
xml部分
<delete id="deleteSysTestByIds" parameterType="String">
delete from sys_test where id in
<foreach collection="array" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
複製代碼
其中foreach包含屬性講解:
dao部分
int deleteSysTestByIds(String[] ids);
複製代碼
service層
@Transactional(rollbackFor = Exception.class)
@Override
public int deleteDictDataByIds(String ids) throws Exception{
try {
return sysTestDao.deleteSysTestByIds(ids.split(","));
} catch (Exception e) {
e.printStackTrace();
throw new Exception();
}
}
複製代碼
controller
@RequestMapping(value = "/deleteIds", method = RequestMethod.POST)
public int deleteIds(String ids) throws Exception {
try {
return sysTestService.deleteDictDataByIds(ids);
} catch (Exception e) {
e.printStackTrace();
throw new Exception();
}
}
複製代碼
請求URL:http://localhost:8081/test/deleteIds
請求報文:
ids : 1,2
複製代碼
多表查詢,多表確定首先咱們先要弄清楚兩個關鍵字:
association: 一對一關聯(has one);collection:一對多關聯(has many)
的各個屬性的含義:
association和collection |
---|
property:映射數據庫列的字段或屬性。 colum:數據庫的列名或者列標籤別名。 javaTyp:完整java類名或別名。 jdbcType:支持的JDBC類型列表列出的JDBC類型。這個屬性只在insert,update或delete的時候針對容許空的列有用。 resultMap:一個能夠映射聯合嵌套結果集到一個適合的對象視圖上的ResultMap。這是一個替代的方式去調用另外一個select語句。 |
這樣提及來可能很差理解,我舉個栗子
涉及到這三張表,我粗略的畫了一下:
- | 用戶表 | 部門表 | 角色表 |
---|---|---|---|
表名 | sys_user | sys_dept | sys_role |
與用戶表關係 | - | 一對一(一個用戶只屬於一個部門) | 一對多(一個用戶能夠有多個角色) |
因而用戶表關聯部門表,咱們用association
用戶表關聯角色表,咱們用collection
固然了,能用得這麼蛋疼關鍵字的前提條件是,你要查詢關聯的字段,若是你只是關聯不查它,那就不須要用這玩意。。
辣麼,我結合這兩個多表查詢的關鍵字association、collection舉個栗子。
@Data
public class SysUser implements Serializable {
private static final long serialVersionUID = 1L;
/** 用戶ID */
private Long userId;
/** 用戶名 */
private String userNameStr;
/** 密碼 */
private String password;
/** 鹽 */
private String salt;
/** 郵箱 */
private String email;
/** 手機號 */
private String mobile;
/** 狀態 0:禁用 1:正常 */
private Integer status;
/** 部門Id */
private Long deptId;
/** 建立時間 */
private Date createTime;
/****************關聯部分************** /** 部門 */
private SysDept dept;
/** 角色集合 */
private List<SysRole> roles;
}
複製代碼
@Data
public class SysDept implements Serializable {
/** 部門ID */
private Long deptId;
/** 部門名稱 */
private String deptName;
}
複製代碼
@Data
public class SysRole implements Serializable {
/** 角色ID */
private Long roleId;
/** 角色名稱 */
private String roleName;
}
複製代碼
List<SysUser> queryUserRoleDept(SysUser user);
複製代碼
<!--查看用戶部門和角色信息-->
<select id="queryUserRoleDept" parameterType="com.niaobulashi.model.SysUser" resultMap="UserResult">
select u.user_id, u.username, u.dept_id, d.dept_name, r.role_id, r.role_name
from sys_user u
LEFT JOIN sys_dept d on d.dept_id = u.dept_id
LEFT JOIN sys_user_role ur on ur.user_id = u.user_id
LEFT JOIN sys_role r on r.role_id = ur.role_id
WHERE 1=1
<if test="userId != null and userId != ''">
AND u.user_id = #{userId}
</if>
</select>
複製代碼
UserResult部分
<!--用戶表-->
<resultMap type="com.niaobulashi.model.SysUser" id="UserResult">
<id property="userId" column="user_id"/>
<result property="userNameStr" column="username"/>
<result property="password" column="login_name"/>
<result property="salt" column="password"/>
<result property="email" column="email"/>
<result property="mobile" column="mobile"/>
<result property="status" column="status"/>
<result property="deptId" column="dept_id"/>
<result property="createTime" column="create_time"/>
<association property="dept" column="dept_id" javaType="com.niaobulashi.model.SysDept" resultMap="DeptResult"/>
<collection property="roles" javaType="java.util.List" resultMap="RoleResult"/>
</resultMap>
<!--部門表-->
<resultMap id="DeptResult" type="com.niaobulashi.model.SysDept">
<id property="deptId" column="dept_id"/>
<result property="deptName" column="dept_name"/>
</resultMap>
<!--角色表-->
<resultMap id="RoleResult" type="com.niaobulashi.model.SysRole">
<id property="roleId" column="role_id"/>
<result property="roleName" column="role_name"/>
</resultMap>
複製代碼
@RequestMapping(value = "/queryUserRoleDept", method = RequestMethod.POST)
private List<SysUser> queryUserRoleDept(@RequestBody SysUser sysUser) {
List<SysUser> userList = sysUserService.queryUserRoleDept(sysUser);
return userList;
}
複製代碼
請求結果:
使用分頁插件PageHelper Spring Boot Starter
,引入maven依賴:PageHelper Spring Boot Starter1.2.12
application.yml配置
# PageHelper分頁插件
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countSql
複製代碼
controller
@RequestMapping(value = "/queryUserByPage", method = RequestMethod.GET)
private PageInfo queryUserByPage(Integer currentPage, Integer pageSize) {
PageHelper.startPage(currentPage, pageSize);
List<SysUser> userList = sysUserService.queryUserRoleDept(new SysUser());
PageInfo info=new PageInfo(userList);
return info;
}
複製代碼
目前暫時寫到這裏,本篇會持續補充
To be continued
做者:鳥不拉屎 出處: https://juejin.im/user/5b3de9155188251aa0161fe4
本文版權歸做者和掘金共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。若是以爲還有幫助的話,能夠點一下左上角的【點贊】。