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語句進(jìn)行對應(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)簽.負(fù)責(zé)將查詢結(jié)果進(jìn)行映射。
- resultType屬性可以指定一個基本類型也可以是一個實體類類型。
- resultType屬性無法與
resultMap屬性
同時出現(xiàn)。
resultMap
MyBatis框架中是根據(jù)表中字段名到實體類定位同名屬性的.如果出現(xiàn)了實體類屬性名與表中字段名不一致的情況,則無法自動進(jì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,如果你是第一個條件,框架會自動幫你把a(bǔ)nd截取, 如果是第二個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負(fù)責(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進(jìn)行配置 --> <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方法
)進(jìn)行對應(yīng)映射,結(jié)果集的數(shù)據(jù)會自動映射給POJO
對象中同名的屬性;
所以當(dāng)我們遇到表的字段名和POJO
屬性名不一致的情況,我們可以在編寫查詢語句的時候,給結(jié)果集的字段取別名,讓別名與POJO
的屬性名一致以保證結(jié)果集的正確映射
全局配置自動識別駝峰式命名規(guī)則
因為我們表中字段的命名規(guī)則采用_
,而POJO
的屬性名命名規(guī)則采用駝峰命名法,所以導(dǎo)致我們在執(zhí)行查詢語句的時候總是要對查詢的字段取別名,以確保正確地進(jìn)行結(jié)果集映射
Mybatis框架
當(dāng)然也注意到了這個問題,所以它提供了一種自動識別駝峰命名規(guī)則的配置,我們只要做了該配置,那么全局的所有查詢語句的執(zhí)行都會自動識別駝峰命名規(guī)則
在Mybatis
全局配置文件加入如下配置:
<!-- 使用settings對Mybatis全局進(jìn)行設(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)系,可以非常靈活地進(jì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:要進(jìn)行映射的結(jié)果集的字段名 2. property:要進(jìn)行映射的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"> <!-- 進(jìn)行一對多映射,使用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)文章
java導(dǎo)出pdf文件的詳細(xì)實現(xiàn)方法
這篇文章主要介紹了java導(dǎo)出pdf文件的詳細(xì)實現(xiàn)方法,包括制作模板、獲取中文字體文件、實現(xiàn)后端服務(wù)以及前端發(fā)起請求并生成下載鏈接,需要的朋友可以參考下2025-03-03springboot?注解方式批量插入數(shù)據(jù)的實現(xiàn)
一次請求需要往數(shù)據(jù)庫插入多條數(shù)據(jù)時,可以節(jié)省大量時間,本文主要介紹了springboot?注解方式批量插入數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03java8 stream自定義分組求和并排序的實現(xiàn)
這篇文章主要介紹了java8 stream自定義分組求和并排序的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01Jackson使用示例-Bean、XML、Json之間相互轉(zhuǎn)換
Jackson是一個強(qiáng)大工具,可用于Json、XML、實體之間的相互轉(zhuǎn)換,JacksonXmlElementWrapper用于指定List等集合類,外圍標(biāo)簽名,JacksonXmlProperty指定包裝標(biāo)簽名,或者指定標(biāo)簽內(nèi)部屬性名,JacksonXmlRootElement指定生成xml根標(biāo)簽的名字,JacksonXmlText指定當(dāng)前這個值2024-05-05