Mybatis配置文件&SQL映射文件 1.配置文件-mybatis-config.xml 1.1基本說明 mybatis的核心配置文件(mybatis-config.xml),它的作用如配置jdbc連接信息,註冊mapper等,我們需要對這個配置文件有詳細的瞭解。 文檔地址:mybatis – M ...
Mybatis配置文件&SQL映射文件
1.配置文件-mybatis-config.xml
1.1基本說明
mybatis的核心配置文件(mybatis-config.xml),它的作用如配置jdbc連接信息,註冊mapper等,我們需要對這個配置文件有詳細的瞭解。
配置文檔的頂層結構如下:
1.2properties(屬性)
屬性可以在外部進行配置,並可以進行動態替換(使用${}
)。既可以在典型的 Java 屬性文件中配置這些屬性,也可以在 properties 元素的子元素中設置。
(1)直接在properties元素的子元素中配置
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?
useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
(2)在外部配置,進行動態替換
jdbc.properties 屬性文件:
.properties 屬性文件需要統一放在 resource 目錄/類載入路徑
# The key value is arbitrary
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
jdbc.user=root
jdbc.pwd=123456
mybatis 配置文件:
要先引入 .properties 文件
<configuration>
<!--引入外部的jdbc.properties-->
<properties resource="jdbc.properties"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.pwd}"/>
</dataSource>
</configuration>
1.3settings(設置)
1.4typeAliases(別名處理器)
- 別名是Java命名一個短名稱,它只和XML配置有關,用來減少類名重覆的部分
- 如果指定了別名,我們的xxMapper.xml文件就可以做相應的簡化處理
- 註意指定別名後,還是可以使用全名的
- 如果一個包下有很多的類,我們可以直接引入包,這樣該包下麵的所有類名都可以直接使用。
<typeAliases>
<!--如果一個包下有很多的類,可以直接使用包的方式引入,這樣包下的所有類名都可以直接使用-->
<package name="com.li.entity"/>
</typeAliases>
1.5typeHandlers(類型處理器)
- 用於Java類型和jdbc類型映射
- Mybatis的映射基本已經滿足,不太需要重新定義
- 這個我們預設即可,也就是mybatis會自動地將java和jdbc類型進行轉換
- Java類型和jdbc類型映射關係一覽 mybatis – MyBatis 3 | 配置
1.6environments(環境)
environments 元素定義瞭如何配置環境。
註意一些關鍵點:
- 預設使用的環境 ID(比如:default="development")。
- 每個 environment 元素定義的環境 ID(比如:id="development")。
- 事務管理器的配置(比如:type="JDBC")。
- 數據源的配置(比如:type="POOLED")。
預設環境和環境 ID 顧名思義。 環境可以隨意命名,但務必保證預設的環境 ID 要匹配其中一個環境 ID。
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<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>
1.7mappers(映射器)
現在就要來定義 SQL 映射語句了。 首先,我們需要告訴 MyBatis 到哪裡去找到這些語句。你可以使用相對於類路徑的資源引用,或完全限定資源定位符(包括 file:///
形式的 URL),或類名和包名等。
(1)使用相對於類路基的資源引用
<!-- 使用相對於類路徑的資源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
(2)使用完全限定資源定位符(URL),不推薦使用
<!-- 使用完全限定資源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
(3)使用映射器介面實現類的完全限定類名
<!-- 使用映射器介面實現類的完全限定類名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
(4)將包內的映射器介面全部註冊為映射器
<!-- 將包內的映射器介面全部註冊為映射器
1.當一個包下有很多的xxMapper.xml文件和基於註解實現的介面時,為了方便,可以用包方式進行引用
2.將下麵的所有xml文件和註解介面都進行註冊-->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
2.SQL映射文件-xxMapper.xml
2.1基本介紹
-
Mybatis 的真正強大之處在於它的語句映射(在XxxMapper.xml中配置),如果拿它和具有相同功能的 JDBC代碼進行對比,你會發現立即省掉了將近 95% 的代碼。MyBatis 致力於減少使用成本,讓用戶能更專註於SQL 代碼。
-
SQL映射文件常用的頂級元素(按照應被定義的順序列出):
-
cache - 該命名空間的緩存配置
-
cache-ref - 引用其他命名空間的緩存配置
-
resultMap - 描述如何從資料庫的結果集 中載入對象,是最複雜也是最強大的元素
-
parameterType - 將會傳入這條語句的參數的類全限定名或別名
-
sql - 可被其他語句引用的可重用語句塊
-
insert - 映射插入語句
-
update - 映射更新語句
-
delete - 映射刪除語句
-
select - 映射查詢語句
-
2.2映射文件詳細說明
2.2.1基本使用
-
insert,delete,update,select 這些在之前講過,分別對應增刪查改的方法和SQL語句的映射
-
如果獲取到剛剛添加的Monster對象的id主鍵(獲取自增長)也講過了
<insert id="addMonster" parameterType="Monster" useGeneratedKeys="true" keyProperty="id"> INSERT INTO `monster` (`age`,`birthday`,`email`,`gender`,`name`,`salary`) VALUES (#{age},#{birthday},#{email},#{gender},#{name},#{salary}) </insert>
2.2.2傳入類型-POJO或String
- 當有多個條件時,傳入的參數設為POJO/Entity類型的 Java對象,這樣可以通過 POJO/Entity 對象的屬性來接收傳入的參數
- 傳入 POJO/Entity 類型時,如果查詢時需要有多個篩選條件,怎麼在映射文件中處理?一般是使用
#{}
的方式來獲取入參的多個值(註意#{}內部的名稱對應的是POJO對象的屬性名,和表欄位無關) - 當傳入的參數類型為String時,則使用
${}
的方式來接收傳入的參數
應用案例
(1)MonsterMapper.java 介面
package com.li.mapper;
import com.li.entity.Monster;
import java.util.List;
/**
* @author 李
* @version 1.0
*/
public interface MonsterMapper {
//通過id或者名字查詢
public List<Monster> findMonsterByNameOrId(Monster monster);
//查詢名字中含有‘精’的妖怪
public List<Monster> findMonsterByName(String name);
}
(2)映射文件MonsterMapper.xml 實現介面方法
<mapper namespace="com.li.mapper.MonsterMapper">
<!--這裡 #{}的值是從傳入的參數的屬性中獲取的,`id`表示表的欄位名,
這裡的parameterType可以直接使用類名,是因為在mybatis的配置文件中配置了別名-->
<select id="findMonsterByNameOrId" parameterType="Monster" resultType="Monster">
SELECT * FROM `monster` WHERE `id` = #{id} OR `name` = #{name}
</select>
<!--當傳入的參數類型為String時,使用${}的方式來接收參數-->
<select id="findMonsterByName" parameterType="String" resultType="Monster">
SELECT * FROM `monster` WHERE `name` LIKE '%${name}%'
</select>
</mapper>
(3)測試
package com.li.mapper;
import com.li.entity.Monster;
import com.li.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
/**
* @author 李
* @version 1.0
*/
public class MonsterMapperTest {
//屬性
private SqlSession sqlSession;
private MonsterMapper monsterMapper;
//初始化
@Before
public void init() {
sqlSession = MybatisUtils.getSqlSession();
monsterMapper = sqlSession.getMapper(MonsterMapper.class);
System.out.println("monsterMapper=" + monsterMapper.getClass());
}
@Test
public void findMonsterByNameOrId() {
Monster monster = new Monster();
monster.setId(1);
monster.setName("狐狸精");
List<Monster> monsters =
monsterMapper.findMonsterByNameOrId(monster);
for (Monster m : monsters) {
System.out.println("m=" + m);
}
if (sqlSession != null) {
sqlSession.close();
}
System.out.println("findMonsterByNameOrId() 查詢成功!");
}
@Test
public void findMonsterByName() {
List<Monster> monsters = monsterMapper.findMonsterByName("精");
for (Monster monster : monsters) {
System.out.println("monster=" + monster);
}
if (sqlSession != null) {
sqlSession.close();
}
System.out.println("findMonsterByName() 查詢成功!");
}
}
2.2.3傳入類型-Map
HashMap傳入參數更加靈活,比如可以靈活地增加查詢的屬性,而不受POJO/Entity 類型本身屬性的限制(因為POJO/Entity 類型的屬性數量有限而且#{}中的名稱必須為屬性名)
例子-演示如何遍歷一個List<Map<String,Object>> 的數據類型
(1)修改MonsterMapper.java,增加方法介面
//聲明一個方法,傳入參數是HashMap,查詢 id>10 並且 salary>40 的所有妖怪
public List<Monster> findMonsterByIdAndSalary(Map<String, Object> map);
(2)修改MonsterMapper.xml映射文件,實現該方法
<!--聲明一個方法,傳入參數是HashMap,查詢 id>5 並且 salary>40 的所有妖怪
這裡使用 #{id}和 #{salary} 來獲取入參 map的值時,意味著你的map需要有key為id和salary的鍵值對
事實上,map的 key 只要和 #{}中的 key一樣即可,和表欄位無關-->
<select id="findMonsterByIdAndSalary" parameterType="map" resultType="Monster">
SELECT * FROM `monster` WHERE `id`>#{id} AND `salary` > #{salary}
</select>
(3)測試
@Test
public void findMonsterByIdAndSalary() {
Map<String, Object> map = new HashMap<>();
map.put("id", 5);//這裡設置的key只要和#{key}的key值一樣即可,和表欄位無關
map.put("salary", 40);
List<Monster> monsters = monsterMapper.findMonsterByIdAndSalary(map);
for (Monster monster : monsters) {
System.out.println("monster=" + monster);
}
if (sqlSession != null) {
sqlSession.close();
}
System.out.println("findMonsterByIdAndSalary() 查詢成功!");
}
2.2.4傳入&返回的類型都是Map
(1)修改MonsterMapper.java,增加方法介面
//傳入和返回的類型都是Map
public List<Map<String, Object>> findMonsterByIdAndSalary2(Map<String, Object> map);
(2)修改MonsterMapper.xml映射文件,實現該方法
<!--查詢 id>5 並且 salary>40 的所有妖怪,要求傳入和返回的參數都是Map類型-->
<select id="findMonsterByIdAndSalary2" parameterType="map" resultType="map">
SELECT * FROM `monster` WHERE `id`>#{id} AND `salary` > #{salary}
</select>
(3)測試
@Test
public void findMonsterByIdAndSalary2() {
Map<String, Object> map = new HashMap<>();
map.put("id", 5);
map.put("salary", 40);
List<Map<String, Object>> monstersList = monsterMapper.findMonsterByIdAndSalary2(map);
//取出返回的結果-以map的形式
for (Map<String, Object> monsterMap : monstersList) {
System.out.println("monsterMap=" + monsterMap);
//遍歷monsterMap,取出屬性和對應的值
for (Map.Entry<String, Object> entry : monsterMap.entrySet()) {
System.out.println("key=" + entry.getKey() + "=>value=" + entry.getValue());
}
}
if (sqlSession != null) {
sqlSession.close();
}
System.out.println("findMonsterByIdAndSalary2() 查詢成功!");
}
2.2.5resultMap結果集映射
當實體類屬性和表的欄位名字不一樣時,我們可以通過resultMap進行映射,從而屏蔽實體類屬性名和表的欄位不一致可能出現的問題。
例子
(1)表user
-- 創建user表
CREATE TABLE `user`(
`user_id` INT NOT NULL AUTO_INCREMENT,
`user_email` VARCHAR(255) DEFAULT '',
`user_name` VARCHAR(255) DEFAULT '',
PRIMARY KEY(`user_id`)
)CHARSET=utf8
(2)創建實體類和表映射,這裡故意設置和表欄位不一樣的屬性名
package com.li.entity;
/**
* @author 李
* @version 1.0
*/
public class User {
private Integer userId;
private String userName;
private String userEmail;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserEmail() {
return userEmail;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", userEmail='" + userEmail + '\'' +
'}';
}
}
(3)創建介面 UserMapper.java
package com.li.mapper;
import com.li.entity.User;
import java.util.List;
/**
* @author 李
* @version 1.0
*/
public interface UserMapper {
//添加
public void addUser(User user);
//查詢所有的User
public List<User> findAllUsers();
}
(4)創建映射文件 UserMapper.xm
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace指定該xml文件和哪個介面對應-->
<mapper namespace="com.li.mapper.UserMapper">
<!--完成添加用戶的任務,註意這裡的user屬性和表的欄位名不一致
這裡的parameterType可以直接使用類名,是因為在mybatis的配置文件中配置了別名-->
<insert id="addUser" parameterType="User">
INSERT INTO `user`(`user_email`,`user_name`)
VALUE(#{userEmail},#{userName});
</insert>
<!--因為表欄位的名稱和實體類型的名稱不一致
1.如果對象屬性名和表欄位不一樣是,那麼返回的數據就保存不進去,就會是對象的屬性就是預設值
2.要解決這個問題,可以使用resultMap來解決這個問題
3.定義一個resultMap,它的id由你指定id,通過id可以引用這個resultMap
4.type 為返回的數據類型(可以使用別名)
5.column為表的欄位,property為對象的屬性名-->
<resultMap id="findAllUserMap" type="User">
<!--指定映射關係-->
<result column="user_email" property="userEmail"/>
<result column="user_name" property="userName"/>
</resultMap>
<select id="findAllUsers" resultMap="findAllUserMap">
SELECT * FROM `user`
</select>
</mapper>
(5)測試
package com.li.mapper;
import com.li.entity.User;
import com.li.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
/**
* @author 李
* @version 1.0
*/
public class UserMapperTest {
//屬性
private SqlSession sqlSession;
private UserMapper userMapper;
//初始化
@Before
public void init() {
sqlSession = MybatisUtils.getSqlSession();
userMapper = sqlSession.getMapper(UserMapper.class);
}
@Test
public void addUser(){
User user = new User();
user.setUserName("marry");
user.setUserEmail("[email protected]");
userMapper.addUser(user);
if (sqlSession != null) {
//需要手動提交事務,因為mybatis事務預設為false
sqlSession.commit();
sqlSession.close();
}
System.out.println("插入成功!");
}
@Test
public void findAllUsers(){
List<User> allUsers = userMapper.findAllUsers();
for (User user : allUsers) {
System.out.println("user="+user);
}
if (sqlSession != null) {
sqlSession.close();
}
System.out.println("查詢成功!");
}
}
resultMap註意事項和細節
-
除了使用resultMap,也可以使用欄位別名解決表欄位和對象屬性不一致的問題,但是它的復用性不好,因此不推薦使用欄位別名
-
如果是MyBatis-Plus處理就比較簡單,可以使用@TableField來解決實體欄位名和表欄位名不一致的問題,還可以使用@TableName來解決實體類名和表名不一致的問題。