1. 程式人生 > 其它 >Mybatis操作詳解

Mybatis操作詳解

Mybatis操作詳解

一、Mybatis的Maven工程操作

1.1、匯入依賴

<!--mysql驅動座標-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!-- mybatis座標 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--日誌座標-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>

1.2、建立Mybatis全域性配置檔案

  • 全域性配置檔案位置

  • 全域性配置檔案

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="datasourse.properties"></properties>
<!-- properties引入外部properties配置檔案內容 resourse 引入類路徑下的檔案,url 引入網路或者磁碟路徑下的資源-->

<environments default="development">
<!-- mybatis可以配置多種環境,mysql和oracle,可以用defaul指定使用環境,實現環境的快速切換 -->
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- mapper:註冊一個sql對映
註冊配置檔案
resourse:引用類路徑下的sql對映檔案
url:引用網路或者磁碟路徑
註冊介面
class:引用(註冊)介面,
1、有sql對映檔案,對映檔名必須和介面同名,並且放在與介面同一目錄下;
2、沒有SQL對映檔案,所有的sql都是利用註解寫在介面上
例如:
@Select("select * from t_user where u_id=#{u_id}")
public User queryById(int id);
注意:寫在配置檔案內方便維護,若是不用維護,較少使用的才用註解。
-->
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>

<!-- 對應的datasourse.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/studentsys?useUnicode=true&characterEncoding=UTF-8
username=root
password=123 -->
  • 其它相關配置標籤

<!-- 是重要的設定項,name表示設定項名,value設定項取值 -->
<settings>
<setting name="" value=""></setting>
</settings>

<!-- 別名處理器:可以為java型別起別名,type是全類名,alias是新起的別名 -->
<typeAliases>
<typeAlias type="" alias=""/>
<!-- package為某個包下所有的類批量起別名,name指定包名(所有類起一個預設別名(類名小寫)) -->
<package name="">
</typeAliases>
@Alias("emp") //別名註釋,寫在類上給類起別名

1.3、建立介面(interface)

public interface UserDao{
public User queryById(int u_id);

public int addUser(int u_id,String u_username,String u_sex);

public int delUser(int u_id);

public int updateUser(int u_id,String u_sex,String u_username);
}

1.4、對映檔案—實現:增刪改查

  • 必須有對應的介面的檔案,對映檔案用於實現介面並完成關係對映

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespcace 命令空間,指定對映的介面檔案 -->
<mapper namespace="dao.UserDao">
<!-- id:方法名稱
parameterType:引數型別
int
String
resultType:表示返回型別,
若是查詢一般是對映的物件。。。
若是增刪改允許定義Integer(表示影響行數)、Long、void、Boolean(表示是否成功,只要一條成功就true)
增刪改查返回值不在配置檔案中設定,直接在介面方法中設定
public boolean addUser(User user);

public int delUser(int id);
-->
<select id="queryById" parameterType="_int"
resultType="pojo.User">
select * from t_user where u_id=#{u_id}
</select>
<insert id="addUser">
insert into t_user values(#{u_id},#{u_username},#{u_sex})
</insert>
<delete id="delUser">
delete from t_user where u_id=#{u_id}
</delete>
<update id="updateUser">
update user set u_id=#{u_id},u_sex=#{u_sex} where username=#{u_username};
</update>
</mapper>

1.5、執行程式,操作資料庫

1.5.1、步驟:

  • 使用全域性配置檔案得到SqlSessionFactory

  • 使用SqlSessionFactory,獲取SqlSession來進行增刪改查,一個SqlSession代表與資料庫的一次會話,用完需要關閉。

  • 根據此方法自動為介面建立一個代理物件,去實現增刪改查功能:

    • UserDao userdao = session.getMapper(UserDao.class);

  • SqlSession和connection都是非執行緒安全,因此每次都要建立新的物件

public class MybatisQueryTest {

public static void main(String[] args) throws IOException {
//1-載入配置檔案
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//2-獲取工廠
SqlSessionFactory factory = new
SqlSessionFactoryBuilder().build(inputStream);
//3-從工廠拿取session
SqlSession session = factory.openSession();
//4-從session裡面拿取mapper
UserDao userdao = session.getMapper(UserDao.class);
//5-業務處理
User user = userdao.queryById(1001);
System.out.println(user);
//6、關閉資源
session.close();
}

}

1.5.2、事務提交—增刪改

  • SqlSession session = factory.openSession();預設為手動提交,

  • 必須新增 session.commit(); 否則會回滾

  • 可以設定為自動提交:factory.openSession(true);

public class MybatisDelTest {

public static void main(String[] args) throws IOException {
//1-載入配置檔案
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//2-獲取工廠
SqlSessionFactory factory = new
SqlSessionFactoryBuilder().build(inputStream);
//3-從工廠拿取session
SqlSession session = factory.openSession();
//4-從session裡面拿取mapper
UserDao userdao = session.getMapper(UserDao.class);
//5-業務處理
int num = userdao.delUser(1015);
System.out.println(num);
//7-提交事務,否則回滾
session.commit();
//6、關閉資源
session.close();
}
}

二、ORM物件關係對映

定義:Object-Relationl Mapping,它的作用是在關係型資料庫和物件之間作一個對映,這樣,我們在具體的操作資料庫的時候,就不需要再去和複雜的SQL語句打交道,只要像平時操作物件一樣操作它就可以了 。

2.1、傳入引數

2.1.1、傳入多個引數

1)預設名稱

介面資訊:

public User query(String name,String sex);  //介面方法

對映檔案:

 <!-- 形參會封裝為一個map,有預設的key,對映檔案可以直接取用 -->
<select id="query" resultType="pojo.User">
select * from t_user where u_name=#{param1} and u_sex=#{param2}
</select>

2)自定義名稱

介面資訊:

//若是形參多,不易辨認,可以通過@Param("name")來對映,這樣封裝map時的key可以自己設定

public User query(@Param("name") String name,@Param("sex") String sex); //介面方法

對映檔案:

 <select id="query" resultType="pojo.User">
select * from t_user where u_name=#{name} and u_sex=#{sex}
</select>

2.1.2、傳入pojo物件

若多個形參均為資料模型pojo的屬性,直接傳入pojo

傳入資料型別設定:parameterType="pojo全類名或者別名",也可以不寫,直接使用#{屬性}呼叫屬性值

介面資訊:

//如果多個引數正好是資料模型pojo,我們可以設定模型引數,直接傳入pojo

public boolean addUser(User user); //介面方法

對映檔案:

<!-- 若傳入的引數為pojo,#{屬性值},直接寫屬性值 -->

<select id="queryMan" resultMap="user">
select * from t_user where u_sex=#{sex}
</select>

方法呼叫:

//建立user
User user = new User();
user.setSex("男");
//業務處理
List<User> list = userdao.queryMan(user);

2.1.3、傳入Map(萬能)

如果多個引數正好是資料模型pojo,我們可以設定模型引數,直接傳入pojo

傳入資料型別設定:parameterType="map",也可以不寫,直接使用#{key}呼叫value

介面資訊:

public User querytree(Map<String,Object> map); //介面方法

對映檔案:

<!-- 若傳入的引數為pojo,#{屬性值},直接寫屬性值 -->
<select id="conditionQuery" resultType="pojo.User" parameterType="map">
select * from t_user where u_name=#{name} and u_sex=#{sex}
</select>

方法呼叫:

//業務處理
Map<String,Object> map = new HashMap();
map.put("name", "自來也");
map.put("sex", "男");
User user = userdao.querytree(map);
System.out.println(user);

2.1.4、傳入TO(Transfer Object)資料傳輸物件

Page{
int index;
int size;
}

2.1.5、注意事項

  • 形參若傳入物件,物件的屬性在對映檔案中也能使用

#{Object.屬性}來獲取
  • Collection(List、set)以及陣列也會封裝進map,List和陣列還能通過索引呼叫

#{List[0]}  //陣列或者list均可如此
  • #{ }和${ }之間的區別

    • #{ }:以預編譯的形式,將引數設定到sql語句中,起PreperStatement的功效,可以防止sql注入。本質就是jdbc裡面的?,一個佔位符。

    • ${ }:是一個直接對映過來的資料,JDBC很多地方不支援佔位符,一般只是引數使用佔位符?,因此需要拼接語句的地方,必須使用${ }。

    • #{ }有更豐富的用法:

      規定引數的一些規則:

      javaType、jdbcType、mode(儲存過程)......

      oracle不能識別null型別
      需要指定型別
      #{email,jdbcType=NULL} 預設jdbcType=OTHER

2、獲取返回型別

2.2.1、返回型別為List

介面資訊:

//介面設定返回資料為List<>

public List<User> queryMan(String sex);

對映檔案:

<!-- 這裡的結果型別不能寫List,寫List內部要封裝的型別 -->

<select id="queryMan" resultType="pojo.User">
select * from t_user where u_sex=#{u_sex}
</select>

2.2.2、返回一個Map

優勢:查詢多欄位,返回一個Map,並且可以指定某屬性作為key

介面資訊:

//指定某欄位作為key
@MapKey("u_id")
public Map<Integer,User> queryWoman(String sex);

對映檔案:

 <select id="queryWoman" resultType="map">   //這裡指定的結果型別為為map
select * from t_user where u_sex=#{u_sex}
</select>

3、新增返回資料對映

<!-- 資料庫返回的欄位與返回結果之間的對映 -->
<resultMap type="pojo.User" id="ouruser">
<id column="u_id" property="id"/>
<result column="u_username" property="username"/>
<result column="u_password" property="password"/>
<result column="u_name" property="name"/>
<result column="u_tel" property="tel"/>
<result column="u_flag" property="flag"/>
<result column="u_image" property="image"/>
<result column="u_login_time" property="logintime"/>
<result column="u_sex" property="sex"/>
<result column="u_age" property="age"/>
</resultMap>

<!-- resultType 換做 resultMap,值寫成result 的 id -->
<select id="queryUser" parameterType="pojo.User" resultMap="ouruser">
select * from t_user where u_sex='男' and u_name=#{name}
</select>

三、關聯查詢

3.1、關聯查詢新增返回資料型別

public class CourseInfo {
private Integer id;
private String date;

//Course的引用資料型別
private Course course;

//Staff的引用資料型別
private Staff teacher;
}

public class Course {
private Integer coId;
private String coName;
private String coType;
private Integer coMaxstu;
private String coPrice;
private String coOncetime;
private String coImage;
private String coDescribe;
private String coBeizhu;
private Integer coFlag;
}

public class Staff {
private Integer staffId;
private String staffName;
private String staffGender;
private String staffTel;
private String staffJob;
private String staffPower;
private String stadium;
private String isLogin;
private String staffState;
}

3.1.1、直接對映

<resultMap id="schedule" type="com.hxzy.course.pojo.Schedule">
<id column="arrange_id" property="id"/>
<result column="date" property="date"/>

<!-- 直接: 引用資料型別屬性.屬性 -->
<id column="co_id" property="course.coId"/>
<result column="co_name" property="course.coName"/>
<result column="co_type" property="course.coType"/>
<result column="co_maxstu" property="course.coMaxstu"/>
<result column="co_price" property="course.coPrice"/>
<result column="co_oncetime" property="course.coOncetime"/>
<result column="co_image" property="course.coImage"/>
<result column="co_describe" property="course.coDescribe"/>
<result column="co_beizhu" property="course.coBeizhu"/>
<result column="co_flag" property="coFlag"/>

<!-- 直接: 引用資料型別屬性.屬性 -->
<result column="staff_id" property="teacher.staffId"/>
<result column="staff_name" property="teacher.staffName"/>
<result column="staff_gender" property="teacher.staffGender"/>
<result column="staff_tel" property="teacher.staffTel"/>
<result column="staff_job" property="teacher.staffJob"/>
<result column="staff_power" property="teacher.staffPower"/>
<result column="stadium" property="teacher.stadium"/>
<result column="is_login" property="teacher.isLogin"/>
<result column="staff_state" property="teacher.staffState"/>
<id column="ti_id" property="tiId"/>
<result column="ti_time" property="teacher.tiTime"/>
</resultMap>

3.1.2、< association >標籤對映

<resultMap id="schedule" type="com.hxzy.course.pojo.Schedule">
<id column="arrange_id" property="id"/>
<result column="date" property="date"/>
<association property="course" javaType="com.hxzy.course.pojo.Course">
<id column="co_id" property="coId"/>
<result column="co_name" property="coName"/>
<result column="co_type" property="coType"/>
<result column="co_maxstu" property="coMaxstu"/>
<result column="co_price" property="coPrice"/>
<result column="co_oncetime" property="coOncetime"/>
<result column="co_image" property="coImage"/>
<result column="co_describe" property="coDescribe"/>
<result column="co_beizhu" property="coBeizhu"/>
<result column="co_flag" property="coFlag"/>
</association>
<association property="teacher" javaType="com.hxzy.course.pojo.Staff">
<id column="staff_id" property="staffId"/>
<result column="staff_name" property="staffName"/>
<result column="staff_gender" property="staffGender"/>
<result column="staff_tel" property="staffTel"/>
<result column="staff_job" property="staffJob"/>
<result column="staff_power" property="staffPower"/>
<result column="stadium" property="stadium"/>
<result column="is_login" property="isLogin"/>
<result column="staff_state" property="staffState"/>
</association>
</resultMap>

3.1.3、< collection >關聯查詢集合封裝

<!-- collection表示返回的型別是個集合 -->
<!-- ofType指定集合內部存放的物件 -->
<collection property="course" ofType="pojo.Course">
<id column="c_id" property="id"></id>
<result column="c_name" property="name"></result>
<result column="c_address" property="address"></result>
<result column="c_flag" property="flag"></result>
</collection>

3.1.4、關聯查詢

<!-- 這裡返回型別同樣使用resultMap -->
<select id="getTuankeSchedule" resultMap="schedule">
SELECT * FROM arrange_course
JOIN course ON arrange_course.co_id = course.co_id
JOIN staff ON arrange_course.staff_id = staff.staff_id
WHERE arrange_course.co_id IN (SELECT co_id FROM course WHERE co_type = '團課')
AND arrange_course.ti_id IS NOT NULL AND arrange_course.DATE IS NOT NULL
</select>

3.2、分步查詢

如何分步:

  • 物件的封裝分為多步,首先查詢封裝非引用資料型別

  • 再進行通過已查詢資料,獲取引用資料型別的相關資料

<mapper namespace="com.hxzy.course.mapper.ScheduleMapper">
<resultMap id="schedule" type="com.hxzy.course.pojo.Schedule">
<id column="arrange_id" property="id"/>
<result column="date" property="date"/>
<result column="co_id" property="coId"/>
<result column="staff_id" property="staffId"/>

<!-- 在介面內新增一個queryCourseById的方法 -->
<!-- select這個引用資料是通過某個介面內的方法查詢得到的 -->
<!-- column是指定傳入查詢語句的引數 -->
<association property="course" select="com.hxzy.course.mapper.ScheduleMapper.queryCourseById" column="co_id">
<id column="co_id" property="coId"/>
<result column="co_name" property="coName"/>
<result column="co_type" property="coType"/>
<result column="co_maxstu" property="coMaxstu"/>
<result column="co_price" property="coPrice"/>
<result column="co_oncetime" property="coOncetime"/>
<result column="co_image" property="coImage"/>
<result column="co_describe" property="coDescribe"/>
<result column="co_beizhu" property="coBeizhu"/>
<result column="co_flag" property="coFlag"/>
</association>
</resultMap>

<select id="getTuankeSchedule" resultMap="schedule">
SELECT * FROM arrange_course
WHERE arrange_course.co_id IN (SELECT co_id FROM course WHERE co_type = '團課')
AND arrange_course.ti_id IS NOT NULL AND arrange_course.DATE IS NOT NULL
</select>

<select id="queryCourseById" resultType="com.hxzy.course.pojo.Course">
SELECT * FROM course
WHERE course.co_id = #{co_id}
</select>
</mapper>

3.3、延遲查詢

定義:在上述引用物件被使用時才會被查詢。

實現方式:

  • 使用了分步查詢

  • 對預設配置進行兩個修改

在全域性檔案中進行設定

<settings>
<!-- 表示關聯的值在使用的時候才會被查詢載入,需要開啟 -->
<setting name="lazyLaodingEnabled" value="true"></setting>
<!-- 表示我們所填屬性會被完整載入,需要關閉 -->
<setting name="aggressiveLazyLoading" value="false"></setting>
</settings>

完成這兩個配置後,我們的分步查詢就變為延遲查詢。分步查詢只做第一步,後續查詢步驟被使用時才會進行

四、動態sql

作用:處理複雜查詢邏輯時,需要動態生成sql語句,這一步可以在java後臺自己進行拼接。而Mybatis已經提供了完整的SQL語句拼接功能。

ps:下面所有的實現方法,傳入的形參均為pojo;一般傳入的是pojo或者map,可以使用屬性名和key來獲取屬性值和value

4.1、< if >標籤

< if >標籤,判斷為真,將查詢語句拼入

<select id="findUserByCondition" parameterMap="user" resultMap="user">
select * from user where type='團課'
<!-- 傳入的是物件,直接輸入屬性 -->
<if test="id!=0">
and id=#{id}
</if>
<if test="username!=null">
and username=#{username}
</if>
</select>

4.2、< where >標籤

作用:< if >標籤的最常用應用場景為條件查詢,而最開頭為where,後面是and,拼接相對不容易。< where >會自行判斷,並刪除第一個 and 或者 or

  • 解決方式一

<select id="findUserByCondition" parameterMap="user" resultMap="user">
<!-- 直接寫 where 1=1 ,後面全部寫 and -->
select * from user where 1=1
<if test="id!=0">
and id=#{id}
</if>
<if test="username!=null">
and username=#{username}
</if>
</select>
  • 解決方式二

<select id="findUserByCondition" parameterMap="user" resultMap="user">
select * from user
<!-- 使用where標籤,它會自己判斷,並消除第一個 and 或 or -->
<where>
<if test="id!=0">
and id=#{id}
</if>
<if test="username!=null">
or username=#{username}
</if>
</where>
</select>

4.3、< trim >標籤

作用:用於解決拼接整體後的前後綴問題:

< trim >的四個屬性:

  • prefix:給拼接後的字串加一個字首

  • prefixOverrides:給拼接後的字串去掉一個字首

  • suffix:給拼接後的字串新增一個字尾

  • suffixOverrides:給拼接後的字串去掉一個字尾

<trim prefix="" prefixOverrides="" suffix="" suffixOverrides=""></trim>

條件查詢的解決方案三:

<!-- 表示在拼接後的字串前方新增一個where,在後方去掉一個and -->
<trim prefix="where" suffixOverrides="and">
<if test="id!=0">
id=#{id} and
</if>
<if test="username!=null">
username=#{username} and
</if>
</trim>

4.4、< choose >分支語句標籤

作用:前端頁面是一個輸入框,輸入框可以輸入姓名、ID、或者其它資訊,輸入一條資訊,但是存在多種可能,這時候的處理就需要分支語句

和< if >的區別:< choose >只能選擇其中一條路走,< if >會都進行判斷

<choose>
<when test="course!=0">
where course.co_id=#{course}
</when>
<when test="teacher!=0">
where staff.staff_id=#{teacher}
</when>
<otherwise>
where 1=1
</otherwise>
</choose>

4.5、< set >標籤

作用:修改屬性時,去除後面的逗號。這裡可以使用< trim >,或者直接用 mybatis-plus 更方便

<update id="updateUser">
update user
<set>
<if test="u_id!=null">
u_id=#{u_id},
</if>
<if test="u_sex!=null">
u_sex=#{u_sex},
</if>
</set>
where username=#{u_username};
</update>

4.6、< foreach >標籤

作用:遍歷傳入的集合

  • collection:指定要遍歷的集合

  • item:將當前遍歷出的元素賦值給指定變數,用#{變數名}能取出變數值即當前遍歷值

  • separator:每個元素直接的分隔符

  • open:遍歷後的結果拼接一個開頭字元

  • close:遍歷後的結果拼接一個結尾字元

  • index:索引

    • 遍歷list的時候,index是索引,item是當前值

    • 遍歷map的時候,index是key,item是map的值

<select id="findUserByIds" parameterType="list" resultMap="user">
select * from user where id in
<foreach collection="array" open="(" close=")" item="id"
separator=",">
#{id}
</foreach>
</select>

4.6.1、mysql環境下的 foreach 批量插入

應用場景:< foreach >標籤也能用於資料批量插入

4.6.2、oracle環境下的 foreach 批量插入