MyBatis Mapper映射文件配置的實現(xiàn)
常用屬性標(biāo)簽
namespace的作用
在MyBatis中,Mapper中的namespace用于綁定Dao接口的,即面向接口編程。 namespace屬性的值要和對應(yīng)的Mapper接口的全限定名保持一致。
namespace的好處在于當(dāng)使用了namespace之后就可以不用寫接口實現(xiàn)類,業(yè)務(wù)邏輯會直接通過這個綁定尋找到相對應(yīng)的SQL語句進行對應(yīng)的數(shù)據(jù)處理。
常用標(biāo)簽介紹
- insert – 映射插入語句
- update – 映射更新語句
- delete – 映射刪除語句
- select – 映射查詢語句
- sql – 可被其他語句引用的可重用語句塊
- resultMap - 確定實體類屬性與表中字段對應(yīng)關(guān)系
parametetType屬性
在<insert>,<update>,<select>,<delete>標(biāo)簽中,可以通過parameterType指定輸入?yún)?shù)的類型,類型可以是簡單類型、hashmap、pojo的包裝類型。
parameterType屬性是可以省略的,MyBatis框架可以根據(jù)SqlSession接口中方法的參數(shù)來判斷輸入?yún)?shù)的實際數(shù)據(jù)類型。
resultType屬性
- resultType屬性存在標(biāo)簽.負責(zé)將查詢結(jié)果進行映射。
- resultType屬性可以指定一個基本類型也可以是一個實體類類型。
- resultType屬性無法與
resultMap屬性同時出現(xiàn)。
resultMap
MyBatis框架中是根據(jù)表中字段名到實體類定位同名屬性的.如果出現(xiàn)了實體類屬性名與表中字段名不一致的情況,則無法自動進行對應(yīng).此時可以使用resultMap來重新建立實體類與字段名之間對應(yīng)關(guān)系
<!--mybatis-config文件配置,可以為一些類定義別名-->
<!--<typeAliases>
<typeAlias type="com.xyxy.pojo.Emp" alias="emp"></typeAlias>
</typeAliases>-->
<!-- type屬性里面使用別名就可以不用全路徑 -->
<resultMap id="empMapper" type="emp">
<id property="empId" column="emp_id"></id>
<result property="empName" column="emp_name"></result>
<result property="empSalary" column="emp_salary"></result>
</resultMap>
<select id="findAll" resultMap="empMapper">
select * from t_emp
</select>
sql
sql:里面可以寫入一個共同的sql代碼,用于提取重復(fù)的代碼。 要使用該代碼的時候就直接使用標(biāo)簽id:為提取的sql代碼,取一個id,起標(biāo)識作用
<!-- 公共代碼 -->
<sql id="select">
<!-- select * from t_emp -->
select emp_id empId,emp_name empName,emp_salary empSalary from t_emp
</sql>
<!--select標(biāo)簽的id與接口的方法名對應(yīng),resultType和返回結(jié)果封裝的Bean一致-->
<select id="findById" resultType="com.xyxy.pojo.Emp">
<!-- include:用于加載提取公共的sql語句,與<sql>標(biāo)簽對應(yīng)
refid:填寫<sql>標(biāo)簽中的id屬性-->
<include refid="select"></include>
where emp_id=#{empId}
</select>
<select id="findByIdOrName" parameterType="Emp" resultType="emp">
<!-- 引入公共代碼 -->
<include refid="select"></include>
<!-- where標(biāo)簽:一個where條件語句,通常和<if>標(biāo)簽混合使用 -->
<where>
<!-- if標(biāo)簽:執(zhí)行一個判斷語句,成立才會執(zhí)行標(biāo)簽體內(nèi)的sql語句,test:寫上條件判斷語句
注意:這里每一個if前面都盡量加上and,如果你是第一個條件,框架會自動幫你把and截取,
如果是第二個if就不能省略and-->
<if test="empId != null and empId != ''">
and emp_id=#{empId}
</if>
<if test="empName != null and empName != ''">
and emp_name like '%${empName}%'
</if>
</where>
</select>
數(shù)據(jù)輸入
在SQL語句中獲取參數(shù)
#{}的方式
Mybatis會在運行過程中,把配置文件中的SQL語句里面的 #{}轉(zhuǎn)換為? 占位符,發(fā)送給數(shù)據(jù)庫執(zhí)行。
配置文件中的SQL
<delete id="deleteEmployeeById" parameterType="int">
delete from t_emp where emp_id=#{empId}
</delete>
實際執(zhí)行的SQL
delete from t_emp where emp_id=?
${}的方式
Mybatis會在運行過程中, 將來會根據(jù)${}拼字符串
配置文件中的SQL語句
<select id="selectEmployeeByName" resultType="com.xyxy.pojo.Employee">
select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_name like '%${empName}%'
</select>
Mapper接口
注意:由于Mapper接口中方法名是作為SQL語句標(biāo)簽的id,不能重復(fù),所以Mapper接口中不能出現(xiàn)重名的方法,不允許重載!
#{}:采用預(yù)編譯方式,可以防止SQL注入${}:采用直接賦值方式,無法阻止SQL注入攻擊
單個簡單類型參數(shù)
Mapper接口中的抽象方法
Employee selectEmployee(Integer empId);
映射配置文件:此時SQL語句中獲取參數(shù)#
<select id="selectEmployee" resultType="com.xyxy.pojo.Employee">
select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{empId}
</select>
多個簡單類型參數(shù)
Mapper接口中抽象方法: 此時每個方法需要使用Param注解命名
int updateEmployee(@Param("empId") Integer empId,@Param("empSalary") Double empSalary);
映射配置文件: 此時SQL語句中獲取參數(shù)#
<update id="updateEmployee">
update t_emp set emp_salary=#{empSalary} where emp_id=#{empId}
</update>
實體類類型參數(shù)
Mapper接口中抽象方法:
int insertEmployee(Employee employee);
映射配置文件: 此時SQL語句獲取參數(shù)#{getXXX方法對應(yīng)的名字,首字母改小寫}
<insert id="insertEmployee">
insert into t_emp(emp_name,emp_salary) values(#{empName},#{empSalary})
</insert>
Mybatis會根據(jù)#{}中傳入的數(shù)據(jù),加工成getXxx()方法,通過反射在實體類對象中調(diào)用這個方法,從而獲取到對應(yīng)的數(shù)據(jù)。填充到#{}這個位置。
Map類型參數(shù)
Mapper接口中抽象方法:
int updateEmployeeByMap(Map<String, Object> paramMap);
映射配置文件: 此時SQL語句獲取參數(shù)#
<update id="updateEmployeeByMap">
update t_emp set emp_salary=#{empSalaryKey} where emp_id=#{empIdKey}
</update>
數(shù)據(jù)輸出
數(shù)據(jù)輸出是針對查詢數(shù)據(jù)的方法返回查詢結(jié)果
返回單個簡單類型數(shù)據(jù)
Mapper接口中的抽象方法: 方法的返回值是簡單數(shù)據(jù)類型
/** * 統(tǒng)計員工數(shù)量 * @return */ Long selectEmployeeCount();
映射配置文件: 此時標(biāo)簽的resultType的類型對應(yīng)抽象方法的返回值類型
<!--
返回簡單類型:
resultType表示結(jié)果類型:結(jié)果集返回的類型,要和Mapper接口中對應(yīng)的方法的返回值類型保持一致
-->
<select id="selectEmployeeCount" resultType="long">
select count(emp_id) from t_emp
</select>
返回一條數(shù)據(jù)
返回實體類對象
Mapper接口中的抽象方法: 方法的返回值是POJO類型
Employee selectEmployee(Integer empId);
映射配置文件: 此時標(biāo)簽的resultType的類型對應(yīng)抽象方法的返回值類型的全限定名
<!-- 編寫具體的SQL語句,使用id屬性唯一的標(biāo)記一條SQL語句 -->
<!-- resultType屬性:指定封裝查詢結(jié)果的Java實體類的全類名 -->
<select id="selectEmployee" resultType="com.xyxy.pojo.Employee">
<!-- Mybatis負責(zé)把SQL語句中的#{}部分替換成“?”占位符 -->
<!-- 給每一個字段設(shè)置一個別名,讓別名和Java實體類中屬性名一致 -->
select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{maomi}
</select>
通過給數(shù)據(jù)庫表字段加別名,讓查詢結(jié)果的每一列都和Java實體類中屬性對應(yīng)起來。
增加全局配置自動映射駝峰命名規(guī)則 在Mybatis的核心配置文件中做下面的配置,select語句中可以不給字段設(shè)置別名
<!-- 在全局范圍內(nèi)對Mybatis進行配置 -->
<settings>
<!-- 具體配置 -->
<!-- 從org.apache.ibatis.session.Configuration類中可以查看能使用的配置項 -->
<!-- 將mapUnderscoreToCamelCase屬性配置為true,表示開啟自動映射駝峰式命名規(guī)則 -->
<!-- 規(guī)則要求數(shù)據(jù)庫表字段命名方式:單詞_單詞 -->
<!-- 規(guī)則要求Java實體類屬性名命名方式:首字母小寫的駝峰式命名 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
返回Map類型
適用于SQL查詢返回的各個字段綜合起來并不和任何一個現(xiàn)有的實體類對應(yīng),沒法封裝到實體類對象中。能夠封裝成實體類類型的,就不使用Map類型。
Mapper接口中的抽象方法: 方法的返回值是Map類型
/** * 根據(jù)empId查詢員工信息,并且將結(jié)果集封裝到Map中 * @param empId * @return */ Map selectEmployeeMapByEmpId(Integer empId);
映射配置文件: 此時標(biāo)簽的resultType的類型為map
<!--
返回Map類型:
resultType表示結(jié)果類型: 就是Map的全限定名或者別名
-->
<select id="selectEmployeeMapByEmpId" resultType="map">
select * from t_emp where emp_id=#{empId}
</select>
返回多行數(shù)據(jù)
返回List<POJO>
查詢結(jié)果返回多個實體類對象,希望把多個實體類對象放在List集合中返回。此時不需要任何特殊處理,在resultType屬性中還是設(shè)置實體類類型即可。
Mapper接口中的抽象方法: 方法的返回值是List<POJO>
List<Employee> selectAll();
映射配置文件: 此時標(biāo)簽的resultType的類型為POJO類的全限定名
<!-- List<Employee> selectAll(); -->
<select id="selectAll" resultType="com.xyxy.pojo.Employee">
select emp_id empId,emp_name empName,emp_salary empSalary from t_emp
</select>
返回List<Map>
查詢結(jié)果返回多個Map對象,希望把多個Map對象放在List集合中返回。此時不需要任何特殊處理,在resultType屬性中還是設(shè)置map即可。
Mapper接口中的抽象方法: 方法的返回值是List<Map>類型
List<Map> selectAllMap();
映射配置文件:此時標(biāo)簽的resultType的類型為map
<select id="selectAllMap" resultType="map">
select emp_id empId,emp_name empName,emp_salary empSalary
from t_emp
</select>
返回自增主鍵
使用場景
例如:保存訂單信息。需要保存Order對象和List<OrderItem>。其中,OrderItem對應(yīng)的數(shù)據(jù)庫表,包含一個外鍵,指向Order對應(yīng)表的主鍵。
在保存List<OrderItem>的時候,需要使用下面的SQL:
insert into t_order_item(item_name,item_price,item_count,order_id) values(...)
這里需要用到的order_id,是在保存Order對象時,數(shù)據(jù)庫表以自增方式產(chǎn)生的,需要特殊辦法拿到這個自增的主鍵值。
實現(xiàn)方案
Mapper接口中的抽象方法:
int insertEmployee(Employee employee);
映射配置文件:
<!-- int insertEmployee(Employee employee); -->
<!-- useGeneratedKeys屬性字面意思就是“使用生成的主鍵” -->
<!-- keyProperty屬性可以指定主鍵在實體類對象中對應(yīng)的屬性名,Mybatis會將拿到的主鍵值存入這個屬性 -->
<insert id="insertEmployee" useGeneratedKeys="true" keyProperty="empId">
insert into t_emp(emp_name,emp_salary)
values(#{empName},#{empSalary})
</insert>
junit測試代碼:
@Test
public void testSaveEmp() {
EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);
Employee employee = new Employee();
employee.setEmpName("john");
employee.setEmpSalary(666.66);
employeeMapper.insertEmployee(employee);
//打印自動返回存入對象的主鍵值
System.out.println("employee.getEmpId() = " + employee.getEmpId());
}
注意:
Mybatis是將自增主鍵的值設(shè)置到實體類對象中,而不是以Mapper接口方法返回值的形式返回。
另一種做法
<insert id="insertEmployee">
insert into t_emp (emp_name,emp_salary) values (#{empName},#{empSalary})
<!--
keyColumn="emp_id"表示要查詢的主鍵的列名
keyProperty="empId"表示將查詢到的主鍵值賦給JavaBean的哪個屬性
resultType="int"表示查詢的結(jié)果類型
order="AFTER" 表示這個查詢是執(zhí)行在insert之前還是之后呢?如果為AFTER表示之后,BEFORE表示之前
-->
<selectKey keyColumn="emp_id" keyProperty="empId" resultType="int" order="AFTER">
select last_insert_id()
</selectKey>
</insert>
不支持自增主鍵的數(shù)據(jù)庫怎么獲取主鍵值
而對于不支持自增型主鍵的數(shù)據(jù)庫(例如 Oracle),則可以使用 selectKey 子元素:selectKey元素將會首先運行,id 會被設(shè)置,然后插入語句會被調(diào)用
<insert id="insertEmployee"
parameterType="com.atguigu.mybatis.beans.Employee"
databaseId="oracle">
<selectKey order="BEFORE" keyProperty="id"
resultType="integer">
select employee_seq.nextval from dual
</selectKey>
insert into orcl_employee(id,last_name,email,gender) values(#{id},#{lastName},#{email},#{gender})
</insert>
或者:
<insert id="insertEmployee"
parameterType="com.atguigu.mybatis.beans.Employee"
databaseId="oracle">
<selectKey order="AFTER" keyProperty="id"
resultType="integer">
select employee_seq.currval from dual
</selectKey>
insert into orcl_employee(id,last_name,email,gender) values(employee_seq.nextval,#{lastName},#{email},#{gender})
</insert>
結(jié)果集的字段和實體類屬性對應(yīng)關(guān)系
自動映射
Mybatis在做結(jié)果集與POJO類的映射關(guān)系的時候,會自動將結(jié)果集的字段名與POJO的屬性名(其實是和getXXX方法)進行對應(yīng)映射,結(jié)果集的數(shù)據(jù)會自動映射給POJO對象中同名的屬性;
所以當(dāng)我們遇到表的字段名和POJO屬性名不一致的情況,我們可以在編寫查詢語句的時候,給結(jié)果集的字段取別名,讓別名與POJO的屬性名一致以保證結(jié)果集的正確映射
全局配置自動識別駝峰式命名規(guī)則
因為我們表中字段的命名規(guī)則采用_,而POJO的屬性名命名規(guī)則采用駝峰命名法,所以導(dǎo)致我們在執(zhí)行查詢語句的時候總是要對查詢的字段取別名,以確保正確地進行結(jié)果集映射
Mybatis框架當(dāng)然也注意到了這個問題,所以它提供了一種自動識別駝峰命名規(guī)則的配置,我們只要做了該配置,那么全局的所有查詢語句的執(zhí)行都會自動識別駝峰命名規(guī)則
在Mybatis全局配置文件加入如下配置:
<!-- 使用settings對Mybatis全局進行設(shè)置 -->
<settings>
<!-- 將xxx_xxx這樣的列名自動映射到xxXxx這樣駝峰式命名的屬性名 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
SQL語句中可以不使用別名:
<!-- Employee selectEmployee(Integer empId); -->
<select id="selectEmployee" resultType="com.atguigu.mybatis.entity.Employee">
select emp_id,emp_name,emp_salary from t_emp where emp_id=#{empId}
</select>
手動映射
使用resultMap標(biāo)簽手動指定結(jié)果集字段與POJO屬性的映射關(guān)系,可以非常靈活地進行結(jié)果集的映射
<!--
手動映射:通過resultMap標(biāo)簽配置映射規(guī)則
1. id屬性:表示這個手動映射規(guī)則的唯一表示
2. type屬性: 表示這個手動映射規(guī)則是將結(jié)果集映射給哪個類的對象,就是JavaBean類的全限定名
resultMap標(biāo)簽中的子標(biāo)簽就是一一指定映射規(guī)則:
1. id標(biāo)簽:指定主鍵的映射規(guī)則
2. result標(biāo)簽:指定非主鍵的映射規(guī)則
id標(biāo)簽和result標(biāo)簽的屬性:
1. column:要進行映射的結(jié)果集的字段名
2. property:要進行映射的JavaBean的屬性名
-->
<resultMap id="EmployeeInfoMap" type="com.xyxy.pojo.EmployeeInfo">
<id column="emp_id" property="id"/>
<result column="emp_name" property="name"/>
<result column="emp_salary" property="salary"/>
</resultMap>
<!--
在select標(biāo)簽中通過resultMap屬性來指定使用哪個手動映射規(guī)則
-->
<select id="selectEmployeeInfoByEmpId" resultMap="EmployeeInfoMap">
select * from t_emp where emp_id=#{empId}
</select>
多表關(guān)聯(lián)查詢
物理建模
CREATE TABLE `t_customer` (
`customer_id` INT NOT NULL AUTO_INCREMENT,
`customer_name` CHAR(100),
PRIMARY KEY (`customer_id`)
);
CREATE TABLE `t_order` (
`order_id` INT NOT NULL AUTO_INCREMENT,
`order_name` CHAR(100),
`customer_id` INT,
PRIMARY KEY (`order_id`)
);
INSERT INTO `t_customer` (`customer_name`) VALUES ('c01');
INSERT INTO `t_customer` (`customer_name`) VALUES ('c02');
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o1', '1');
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o2', '1');
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o3', '1');
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o4', '2');
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o5', '2');
t_customer表和t_order表示一對多關(guān)系,反之t_order表和t_customer表可以看成一對一或者多對一關(guān)系
一對一或多對一查詢
任務(wù)
根據(jù)訂單ID查詢出訂單信息,并且查詢出該訂單所屬的顧客信息,將查詢到的結(jié)果集封裝到Order對象中
POJO封裝結(jié)果集
public class Order {
private Integer orderId;
private String orderName;
//表示Order和Customer的對一關(guān)系
private Customer customer;
}
public class Customer {
private Integer customerId;
private String customerName;
}
接口方法
public interface OrderMapper{
Order findByOrderId(Integer orderId);
}
在全局配置文件中配置
<!--全局配置自動映射駝峰命名-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--實體類取別名-->
<typeAliases>
<package name="com.xyxy.pojo"/>
</typeAliases>
<!-- Mapper注冊:指定Mybatis映射文件的具體位置 -->
<!-- mappers標(biāo)簽:配置一個具體的Mapper映射文件 -->
<!-- resource屬性:指定Mapper映射文件的實際存儲位置,這里需要使用一個以類路徑根目錄
<mappers>
<!-- 包下的所有Mapper配置文件將被自動加載、注冊,比較方便。 -->
<package name="com.xyxy.mapper"/>
</mappers>
映射配置文件OrderMapper.xml
<?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">
<mapper namespace="com.xyxy.mapper.OrderMapper">
<resultMap id="order" type="Order" autoMapping="true">
<!-- autoMapping屬性設(shè)置為true開啟自動映射 -->
<association property="customer" javaType="Customer">
<id column="customer_id" property="customerId"></id>
<result column="customer_name" property="customerName"></result>
</association>
</resultMap>
<select id="findByOrderId" resultMap="order">
select * from t_order o left join t_customer c on o.customer_id=c.customer_id where order_id=#{orderId}
</select>
</mapper>
一對多查詢
任務(wù)
根據(jù)客戶的ID查詢客戶信息,并且查詢出該客戶的所有訂單信息,將查詢的訂單信息結(jié)果集封裝到Customer對象中
POJO封裝結(jié)果集
public class Customer {
private Integer customerId;
private String customerName;
//客戶和訂單的一對多關(guān)系
private List<Order> orderList;
}
public class Order {
private Integer orderId;
private String orderName;
}
CustomerMapper接口中的抽象方法
public interface CustomerMapper {
Customer findCustomerAndOrders(Integer customerId);
}
映射配置文件CustomerMapper.xml
<?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">
<mapper namespace="com.xyxy.mapper.CustomerMapper">
<resultMap id="customer" type="Customer" >
<id column="customer_id" property="customerId"/>
<result column="customer_name" property="customerName"/>
<collection property="orderList" ofType="Order" autoMapping="true">
<!--
進行一對多映射,使用collection標(biāo)簽
ofType屬性指的是orderList的泛型
-->
</collection>
</resultMap>
<select id="findCustomerAndOrders" resultMap="customer">
SELECT * FROM t_customer c,t_order o WHERE o.customer_id=c.customer_id AND c.customer_id=#{customerId}
</select>
</mapper>
到此這篇關(guān)于MyBatis Mapper映射文件配置的實現(xiàn)那的文章就介紹到這了,更多相關(guān)MyBatis Mapper映射文件配置內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
談?wù)凷pring AOP中@Aspect的高級用法示例
在Spring AOP中目前只有執(zhí)行方法這一個連接點,下面這篇文章主要給大家介紹了關(guān)于Spring AOP中@Aspect的高級用法的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08
springboot2.1.7去除json返回字段中為null的字段
這篇文章主要介紹了springboot2.1.7去除json返回字段中為null的字段,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
java組件SmartUpload和FileUpload實現(xiàn)文件上傳功能
這篇文章主要為大家詳細介紹了java組件SmartUpload和FileUpload實現(xiàn)文件上傳功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11

