1.MyBatis高級映射:
MyBatis的高級映射是指在MyBatis中使用更加靈活和強大的技術(shù)來實現(xiàn)數(shù)據(jù)持久化和對象關(guān)系映射的方式。高級映射包括以下幾種技術(shù):
動態(tài)SQL:可以根據(jù)不同的條件動態(tài)生成SQL語句。
嵌套查詢:可以在一個查詢語句中嵌套另一個查詢語句,實現(xiàn)復雜的查詢操作。
延遲加載:可以在需要時才去加載關(guān)聯(lián)對象,減少數(shù)據(jù)庫的訪問次數(shù),提高性能。
自動映射:可以根據(jù)數(shù)據(jù)庫表和Java類的命名規(guī)則自動映射屬性和字段。
緩存:可以將查詢結(jié)果緩存到內(nèi)存中,提高查詢性能。
批量操作:可以將多個操作一起提交到數(shù)據(jù)庫,提高數(shù)據(jù)庫操作效率。
這些高級映射技術(shù)可以讓開發(fā)人員更加方便地使用MyBatis來實現(xiàn)數(shù)據(jù)持久化和對象關(guān)系映射,提高開發(fā)效率和系統(tǒng)性能。
1.1 相關(guān)XML標簽及其屬性:
(1)mapper標簽:
MyBatis中的mapper標簽是用來定義SQL語句和映射關(guān)系的,它可以將SQL語句和Java方法綁定起來,實現(xiàn)數(shù)據(jù)的持久化和對象關(guān)系映射。在使用MyBatis時,通常會將mapper標簽定義在XML文件中,然后通過SqlSessionFactory加載和解析XML文件,創(chuàng)建SqlSession對象進行數(shù)據(jù)庫操作。
具體來說,mapper標簽包含了一組SQL語句和映射關(guān)系,可以通過namespace屬性來指定命名空間,通過id屬性來指定SQL語句的唯一標識符。在mapper標簽內(nèi)部,可以使用select、insert、update、delete等標簽來定義具體的SQL語句和參數(shù)映射關(guān)系。例如:
<mapper namespace="com.example.UserMapper">
<select id="getUserById" parameterType="int" resultType="com.example.User">
SELECT * FROM user WHERE id = #{id}
</select>
<insert id="insertUser" parameterType="com.example.User" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user(name, age) VALUES(#{name}, #{age})
</insert>
<update id="updateUser" parameterType="com.example.User">
UPDATE user SET name = #{name}, age = #{age} WHERE id = #{id}
</update>
<delete id="deleteUser" parameterType="int">
DELETE FROM user WHERE id = #{id}
</delete>
</mapper>
上面的例子中,mapper標簽定義了一個命名空間為com.example.UserMapper的mapper,包含了四個SQL語句和對應的參數(shù)映射關(guān)系。
其中,
select標簽定義了一個id為getUserById的SQL語句,使用了一個int類型的參數(shù)id和一個com.example.User類型的返回值。
insert標簽定義了一個id為insertUser的SQL語句,使用了一個com.example.User類型的參數(shù),并且開啟了自動生成主鍵的功能。
update標簽定義了一個id為updateUser的SQL語句,使用了一個com.example.User類型的參數(shù)。
delete標簽定義了一個id為deleteUser的SQL語句,使用了一個int類型的參數(shù)id。
(2)DOCTYPE標簽:
MyBatis配置文件中的DOCTYPE聲明,它指定了MyBatis配置文件的DTD(Document Type Definition),用于驗證和解析XML文件的結(jié)構(gòu)和內(nèi)容。它的作用是告訴XML解析器使用指定的DTD來驗證和解析XML文件,確保XML文件的結(jié)構(gòu)和內(nèi)容符合規(guī)范。如果XML文件的結(jié)構(gòu)和內(nèi)容不符合DTD的規(guī)范,解析器會報錯并停止解析。它不是必須的,但建議在MyBatis配置文件中使用,以確保XML文件的正確性和可讀性。
下面是一個示例MyBatis配置文件,包含了DOCTYPE聲明:
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/example/UserMapper.xml"/>
</mappers>
</configuration>
上面的例子中,DOCTYPE聲明指定了MyBatis 3.0版本的DTD,確保XML文件的結(jié)構(gòu)和內(nèi)容符合規(guī)范。configuration標簽是MyBatis配置文件的根元素,包含了environments和mappers兩個子元素,用于配置數(shù)據(jù)庫環(huán)境和SQL映射文件。
(3)typeAliases標簽:
MyBatis中的標簽用于給Java類型起別名,方便在映射文件中使用。具體來說,
<typeAliases>
標簽可以將Java類型的全限定名或簡單類名映射為一個自定義的別名,然后在映射文件中使用別名代替Java類型的全限定名或簡單類名,提高代碼的可讀性和可維護性。
標簽有以下兩個屬性:
- typeHandlerPackage:指定自動掃描的類型處理器所在的包名。
- alias:指定Java類型的別名,格式為"別名=全限定名"或"別名=簡單類名"。
標簽可以包含以下兩個子標簽:
- :用于指定自動掃描的Java類型所在的包名??梢允褂?通配符指定多個包名,例如:。
- :用于指定Java類型的別名和全限定名或簡單類名。例如:。
下面是一個示例標簽的用法:
<typeAliases>
<package name="com.example.model"/>
<typeAlias type="com.example.User" alias="User"/>
<typeAlias type="com.example.Order" alias="Order"/>
</typeAliases>
上面的例子中,<typeAliases
>標簽指定了自動掃描com.example.model包下的所有Java類型,
并將com.example.User和com.example.Order兩個Java類型分別映射為User和Order兩個別名。
這樣,在映射文件中,我們就可以使用User和Order這兩個別名代替Java類型的全限定名或簡單類名,例如:
<select id="getUserById" parameterType="int" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>
<insert id="insertOrder" parameterType="Order">
INSERT INTO order(order_no, user_id) VALUES(#{orderNo}, #{userId})
</insert>
需要注意的是,
- 使用標簽自動映射Java類型時,別名的默認值是Java類型的簡單類名,可以通過標簽來指定自定義的別名。
- 標簽可以定義在MyBatis配置文件中,也可以定義在映射文件中。如果定義在MyBatis配置文件中,則可以在所有映射文件中使用別名;如果定義在映射文件中,則只能在當前映射文件中使用別名。
(4)mappers標簽:
MyBatis中的
<mappers
>標簽用于指定映射文件的位置或通過Java接口來聲明映射關(guān)系。
具體來說,標簽可以包含以下兩個子標簽:
- mapper:用于指定映射文件的位置或通過Java接口來聲明映射關(guān)系??梢允褂胷esource、url、class三種方式來指定映射文件或Java接口,例如:
<mapper resource="com/example/UserMapper.xml"/>
。 - package:用于指定自動掃描的映射文件所在的包名??梢允褂?通配符指定多個包名,例如:
<package name="com.example.*"/>
。
標簽還有以下兩個屬性:
- enableLazyLoading:指定是否開啟延遲加載,默認值為false。
- defaultStatementTimeout:指定默認的SQL語句超時時間,單位為秒。
下面是一個示例標簽的用法:
<mappers>
<mapper resource="com/example/UserMapper.xml"/>
<mapper class="com.example.OrderMapper"/>
<package name="com.example.mapper"/>
</mappers>
上面的例子中,<mappers>
標簽指定了三種方式來聲明映射關(guān)系:
通過resource屬性指定了一個映射文件com/example/UserMapper.xml;
通過class屬性指定了一個 Java接口com.example.OrderMapper;
通過package標簽指定了一個自動掃描的包com.example.mapper。
這樣,在MyBatis啟動時,會自動加載并解析這些映射文件或Java接口,建立映射關(guān)系,以便在后續(xù)的數(shù)據(jù)庫操作中使用。
需要注意的是,標簽可以定義在MyBatis配置文件中,也可以定義在映射文件中。如果定義在MyBatis配置文件中,則可以在所有映射文件中使用;如果定義在映射文件中,則只能在當前映射文件中使用。
(5)resultMap標簽:
MyBatis 中,resultMap 是一個映射結(jié)果集的標簽,用于將 SQL 查詢結(jié)果映射到 Java 對象中。resultMap標簽可以定義在xml映射文件中,也可以定義在 Java 接口或抽象類中。
resultMap 標簽有以下屬性:
- id:標識 resultMap 的唯一標識符,必須指定。
- type:指定映射結(jié)果集的返回類型,可以是 Java 類型或別名,必須指定。
- extends:指定繼承的 resultMap 的 id,可選屬性。
resultMap 標簽有以下子標簽:
- id:用于映射主鍵字段。
- result:用于映射普通字段。
- association:用于關(guān)聯(lián)另一個 resultMap。
- collection:用于映射集合屬性。
下面是一個 resultMap 的示例:
<resultMap id="userMap" type="User">
<id column="id" property="id" />
<result column="username" property="username" />
<result column="password" property="password" />
<result column="email" property="email" />
<association property="profile" resultMap="profileMap" />
<collection property="orders" ofType="Order">
<id column="id" property="id" />
<result column="order_no" property="orderNo" />
<result column="total_price" property="totalPrice" />
</collection>
</resultMap>
上面的例子中,
resultMap 標簽的 id 屬性為 “userMap”,type 屬性為 “User”,表示將 SQL 查詢結(jié)果映射到 User 類型的對象中。
其中,
id 子標簽映射主鍵字段,
result 子標簽映射普通字段,
association 子標簽映射關(guān)聯(lián)對象,
collection 子標簽映射集合屬性。其中,
association 子標簽使用了另一個 resultMap,
即 “profileMap”,用于映射 User 類型中的 profile 屬性。
collection 子標簽的 ofType 屬性指定集合元素的類型,即 Order 類型。
在使用 resultMap 時,可以在 SQL 映射語句中使用 resultMap 屬性指定要使用的 resultMap,例如:
<select id="getUser" resultMap="userMap">
SELECT * FROM user WHERE id = #{id}
</select>
(6)association標簽:
MyBatis中,association是一種結(jié)果映射的方式,用于建立兩個Java對象之間的多對一關(guān)系。當查詢結(jié)果中包含了關(guān)聯(lián)對象的信息時,可以使用association將關(guān)聯(lián)對象映射到主對象的屬性上。
association有以下常用屬性:
- property:指定主對象中的關(guān)聯(lián)對象屬性名。
- javaType:指定關(guān)聯(lián)對象的Java類型。
- columnPrefix:指定關(guān)聯(lián)對象在查詢結(jié)果中的列名前綴。
- resultMap:指定關(guān)聯(lián)對象的結(jié)果映射。
舉個例子,假設有兩個Java對象Product和Category,它們之間是多對一關(guān)系,即一個商品屬于一個分類,一個分類下有多個商品。那么可以定義如下的association:
<resultMap type="Product" id="productBean">
<id column="pid" property="id" />
<result column="pname" property="name" />
<result column="price" property="price" />
<association property="category" javaType="Category">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
</association>
</resultMap>
在上面的代碼中,association定義了Product對象(java)中的category屬性,類型為Category。
當查詢結(jié)果中包含了Category對象的信息時,MyBatis會自動將Category對象映射到Product對象的category屬性上。
其中,id和result分別定義了Category對象的主鍵和普通屬性的映射關(guān)系。這樣,在查詢Product對象時,就可以同時獲取到關(guān)聯(lián)的Category對象的信息了。
簡單來說,association用于聲明外鍵。
(7)collection:
MyBatis中,collection是一種結(jié)果映射的方式,用于建立兩個Java對象之間的一對多關(guān)系。當查詢結(jié)果中包含了關(guān)聯(lián)對象的集合信息時,可以使用collection將關(guān)聯(lián)對象集合映射到主對象的屬性上。
collection有以下常用屬性:
- property:指定主對象中的關(guān)聯(lián)對象集合屬性名。
- ofType:指定關(guān)聯(lián)對象集合中的元素類型。
- columnPrefix:指定關(guān)聯(lián)對象在查詢結(jié)果中的列名前綴。
- resultMap:指定關(guān)聯(lián)對象的結(jié)果映射。
舉個例子,假設有兩個Java對象Category和Product,它們之間是一對多關(guān)系,即一個分類下有多個商品。那么可以定義如下的collection:
<resultMap type="Category" id="categoryBean">
<id column="cid" property="id" />
<result column="cname" property="name" />
<collection property="products" ofType="Product">
<id column="pid" property="id"/>
<result column="pname" property="name"/>
<result column="price" property="price"/>
</collection>
</resultMap>
在上面的代碼中,collection定義了Category對象中的products屬性,類型為List。
當查詢結(jié)果中包含了Category對象和其關(guān)聯(lián)的Product對象集合時,
MyBatis會自動將Product對象集合映射到Category對象的products屬性上。
其中,id和result分別定義了Product對象的主鍵和普通屬性的映射關(guān)系。
這樣,在查詢Category對象時,就可以同時獲取到其關(guān)聯(lián)的Product對象集合信息了。
1.2 多對多:
(1)先知:
how2j上給定地是一個商品-商品種類-訂單項-訂單的模型
這里簡單解釋一下訂單和訂單項目:
訂單是指客戶向商家提交的購買請求,包含了購買的商品、數(shù)量、價格、支付方式、收貨地址等信息。一般來說,訂單會被分配一個唯一的訂單號,以便于商家和客戶對訂單進行跟蹤和管理。
訂單項是指訂單中的一個商品條目,包含了購買的商品、數(shù)量、價格等信息。一個訂單可以包含多個訂單項,每個訂單項對應一個商品。因此,訂單項是訂單的組成部分,用于記錄訂單中每個商品的詳細信息。
實現(xiàn)一對多,是通過collection標簽實現(xiàn)的,
實現(xiàn)多對一,是通過association標簽實現(xiàn)的,
那么,實現(xiàn)多對多就需要collection和association一起使用,更具體的說,是嵌套使用,即“嵌套結(jié)果映射”。
下方是我們希望在控制臺呈現(xiàn)的內(nèi)容與結(jié)構(gòu)
code000A
product a 88.879997 100
product b 88.879997 101
product c 88.879997 102
進一步抽象,得到
訂單號—訂單項—商品,
故我們需要配置的映射文件的結(jié)構(gòu)應該如下圖紅色指示線所示
因此how2j上提供的映射配置文件中的內(nèi)容是有很多無用部分的,這些部分是為前兩節(jié)“一對多”和“多對一“服務的,比如說Category.xml的association標簽及其包含內(nèi)容,在多對多映射中,我們根本不需要product去關(guān)聯(lián)category,因此這些無用標簽刪去后也可正常運行測試類,為了不增加工作量,我沒有刪除,但是測試了幾個,確實是可以刪除并正常運行的,這就說明我的理解沒有出錯。
文件目錄結(jié)構(gòu)如圖所示:
(2)實體類文件:
Category.java:
package com.how2java.pojo;
import java.util.List;
public class Category {
// 分類id
private int id;
// 分類名稱
private String name;
// 分類下的商品列表
List<Product> products;
// 獲取分類id的方法
public int getId() {
return id;
}
// 設置分類id的方法
public void setId(int id) {
this.id = id;
}
// 獲取分類名稱的方法
public String getName() {
return name;
}
// 設置分類名稱的方法
public void setName(String name) {
this.name = name;
}
// 獲取分類下的商品列表的方法
public List<Product> getProducts() {
return products;
}
// 設置分類下的商品列表的方法
public void setProducts(List<Product> products) {
this.products = products;
}
// 重寫toString方法,用于打印分類信息
@Override
public String toString() {
return "Category [id=" + id + ", name=" + name + "]";
}
}
Order.java:
// 定義Order類
package com.how2java.pojo;
import java.util.List;
// Order類
public class Order {
// 訂單id
private int id;
// 訂單編號
private String code;
// 訂單項列表
List<OrderItem> orderItems;
// 獲取訂單id
public int getId() {
return id;
}
// 設置訂單id
public void setId(int id) {
this.id = id;
}
// 獲取訂單編號
public String getCode() {
return code;
}
// 設置訂單編號
public void setCode(String code) {
this.code = code;
}
// 獲取訂單項列表
public List<OrderItem> getOrderItems() {
return orderItems;
}
// 設置訂單項列表
public void setOrderItems(List<OrderItem> orderItems) {
this.orderItems = orderItems;
}
}
OrderItem.java:
// 定義OrderItem類
package com.how2java.pojo;
// OrderItem類
public class OrderItem {
// 訂單項id
private int id;
// 訂單項數(shù)量
private int number;
// 訂單
private Order order;
// 商品
private Product product;
// 獲取訂單項id
public int getId() {
return id;
}
// 設置訂單項id
public void setId(int id) {
this.id = id;
}
// 獲取訂單項數(shù)量
public int getNumber() {
return number;
}
// 設置訂單項數(shù)量
public void setNumber(int number) {
this.number = number;
}
// 獲取訂單
public Order getOrder() {
return order;
}
// 設置訂單
public void setOrder(Order order) {
this.order = order;
}
// 獲取商品
public Product getProduct() {
return product;
}
// 設置商品
public void setProduct(Product product) {
this.product = product;
}
}
Product.java:
package com.how2java.pojo;
public class Product {
private int id; // 產(chǎn)品的唯一標識符,用于識別不同的產(chǎn)品
private String name; // 產(chǎn)品的名稱,用于描述產(chǎn)品的特征
private float price; // 產(chǎn)品的價格,用于表示產(chǎn)品的價值
private Category category; // 產(chǎn)品所屬的類別,用于分類管理產(chǎn)品
public Category getCategory() { // 獲取產(chǎn)品所屬的類別
return category;
}
public void setCategory(Category category) { // 設置產(chǎn)品所屬的類別
this.category = category;
}
public int getId() { // 獲取產(chǎn)品的唯一標識符
return id;
}
public void setId(int id) { // 設置產(chǎn)品的唯一標識符
this.id = id;
}
public String getName() { // 獲取產(chǎn)品的名稱
return name;
}
public void setName(String name) { // 設置產(chǎn)品的名稱
this.name = name;
}
public float getPrice() { // 獲取產(chǎn)品的價格
return price;
}
public void setPrice(float price) { // 設置產(chǎn)品的價格
this.price = price;
}
@Override
public String toString() { // 重寫toString方法,用于打印產(chǎn)品信息
return "Product [id=" + id + ", name=" + name + ", price=" + price + "]";
}
}
(3)xml配置文件:
mybatis-config.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 聲明XML版本和編碼 -->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--
MyBatis 配置文件的 DTD 聲明,用于驗證 XML 配置文件是否符合 MyBatis 的語法規(guī)范。
-->
<configuration>
<!-- 聲明類型別名,用于簡化 Java 類型的命名,方便在 XML 中引用。 -->
<typeAliases>
<package name="com.how2java.pojo"/>
</typeAliases>
<!-- 聲明環(huán)境,用于定義 MyBatis 的運行環(huán)境,包括事務管理器和數(shù)據(jù)源等。 -->
<environments default="development">
<environment id="development">
<!-- 聲明事務管理器類型,用于管理數(shù)據(jù)庫事務,包括開啟、提交、回滾等操作。 -->
<transactionManager type="JDBC"/>
<!-- 聲明數(shù)據(jù)源類型,用于連接數(shù)據(jù)庫,包括數(shù)據(jù)庫驅(qū)動、URL、用戶名和密碼等信息。 -->
<dataSource type="POOLED">
<!-- 數(shù)據(jù)庫驅(qū)動 -->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!-- 數(shù)據(jù)庫連接URL -->
<property name="url" value="jdbc:mysql://localhost:3306/how2java?characterEncoding=UTF-8"/>
<!-- 數(shù)據(jù)庫用戶名 -->
<property name="username" value="root"/>
<!-- 數(shù)據(jù)庫密碼 -->
<property name="password" value="admin"/>
</dataSource>
</environment>
</environments>
<!-- 聲明映射器,用于定義數(shù)據(jù)庫操作的 SQL 語句和映射關(guān)系。 -->
<mappers>
<mapper resource="com/how2java/pojo/Product.xml"/>
<mapper resource="com/how2java/pojo/Category.xml"/>
<mapper resource="com/how2java/pojo/Order.xml"/>
<mapper resource="com/how2java/pojo/OrderItem.xml"/>
</mappers>
</configuration>
(4)xml映射文件:
Category.java:
<?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.how2java.pojo">
<!-- 定義 resultMap,用于將查詢結(jié)果映射到 Category 對象中 -->
<resultMap type="Category" id="categoryBean">
<!-- id 標簽用于指定對象的主鍵屬性,
column 屬性指定了查詢結(jié)果中的列名,
property 屬性指定了對象中的屬性名 -->
<id column="cid" property="id" />
<!-- result 標簽用于指定對象的其他屬性,
column 和 property 屬性的含義與 id 標簽相同 -->
<result column="cname" property="name" />
<!-- 一對多的關(guān)系,
collection 標簽用于指定集合屬性的名稱和類型 -->
<!-- property 屬性指定了主對象集合屬性的名稱,
ofType 屬性指定了關(guān)聯(lián)對象集合中元素的類型 -->
<collection property="products" ofType="Product">
<!-- id 標簽用于指定集合元素的主鍵屬性,
column 和 property 屬性的含義與 id 標簽相同 -->
<id column="pid" property="id" />
<!-- result 標簽用于指定集合元素的其他屬性,
column 和 property 屬性的含義與 result 標簽相同 -->
<result column="pname" property="name" />
<result column="price" property="price" />
</collection>
</resultMap>
<!-- 關(guān)聯(lián)查詢分類和產(chǎn)品表 -->
<!-- id 屬性指定了 SQL 語句的唯一標識符 -->
<!-- resultMap 屬性指定了查詢結(jié)果映射的 resultMap 的唯一標識符 -->
<select id="listCategory" resultMap="categoryBean">
<!-- 使用 left join 連接分類表和產(chǎn)品表 -->
<!-- c.*, p.* 表示查詢分類表和產(chǎn)品表的全部列 -->
<!-- 別名語法用于將查詢結(jié)果中的列映射到對象的屬性中 -->
<!-- column 屬性指定了查詢結(jié)果中的列名,'cid'、'pid'、'cname'、'pname' 是別名 -->
<!-- property 屬性指定了對象中的屬性名 -->
select c.*, p.*, c.id 'cid', p.id 'pid', c.name 'cname', p.name 'pname'
from category_ c
left join product_ p on c.id = p.cid
</select>
<!-- 定義一個名為addCategory的插入操作,參數(shù)類型為Category -->
<insert id="addCategory" parameterType="Category" >
insert into category_ ( name ) values (#{name})
</insert>
<!-- 定義一個名為deleteCategory的刪除操作,參數(shù)類型為Category -->
<delete id="deleteCategory" parameterType="Category" >
delete from category_ where id= #{id}
</delete>
<!-- 定義一個名為getCategory的查詢操作,參數(shù)類型為int,結(jié)果類型為Category -->
<select id="getCategory" parameterType="_int" resultType="Category">
select * from category_ where id= #{id}
</select>
<!-- 定義一個名為updateCategory的更新操作,參數(shù)類型為Category -->
<update id="updateCategory" parameterType="Category" >
update category_ set name=#{name} where id=#{id}
</update>
<!-- 定義一個名為listCategory的查詢操作,結(jié)果類型為Category -->
<select id="listCategory1" resultType="Category">
select * from category_
</select>
<!-- 定義一個名為listCategoryByName的查詢操作,參數(shù)類型為string,結(jié)果類型為Category -->
<select id="listCategoryByName" parameterType="string" resultType="Category">
select * from category_ where name like concat('%',#{0},'%')
</select>
<select id="listCategoryByIdAndName" parameterType="map" resultType="Category">
select * from category_ where id> #{id} and name like concat('%',#{name},'%')
</select>
</mapper>
Order.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文件,指定命名空間為com.how2java.pojo -->
<mapper namespace="com.how2java.pojo">
<!-- 定義結(jié)果映射,type指定結(jié)果映射的Java類型,id指定結(jié)果映射的唯一標識 -->
<resultMap type="Order" id="orderBean">
<!-- 定義主鍵,column指定數(shù)據(jù)庫表中的列名,property指定Java對象中的屬性名 -->
<id column="oid" property="id" />
<!-- 定義普通屬性,column指定數(shù)據(jù)庫表中的列名,property指定Java對象中的屬性名 -->
<result column="code" property="code" />
<!-- 定義集合屬性,property指定Java主對象中的集合屬性名,ofType指定關(guān)聯(lián)對象集合元素的Java類型 -->
<!-- 一對多 -->
<collection property="orderItems" ofType="OrderItem">
<!-- 定義集合元素的主鍵,column指定數(shù)據(jù)庫表中的列名,property指定Java對象中的屬性名 -->
<id column="oiid" property="id" />
<!-- 定義集合元素的普通屬性,column指定數(shù)據(jù)庫表中的列名,property指定Java對象中的屬性名 -->
<result column="number" property="number" />
<!-- 定義集合元素的關(guān)聯(lián)對象,property指定Java主對象中的對象屬性名,javaType指定關(guān)聯(lián)對象的Java類型 -->
<!-- 多對1 -->
<association property="product" javaType="Product">
<!-- 定義關(guān)聯(lián)對象的主鍵,column指定數(shù)據(jù)庫表中的列名,property指定Java對象中的屬性名 -->
<id column="pid" property="id"/>
<!-- 定義關(guān)聯(lián)對象的普通屬性,column指定數(shù)據(jù)庫表中的列名,property指定Java對象中的屬性名 -->
<result column="pname" property="name"/>
<result column="price" property="price"/>
</association>
</collection>
</resultMap>
<!-- 定義查詢語句,id指定查詢語句的唯一標識,resultMap指定結(jié)果映射的唯一標識 -->
<select id="listOrder" resultMap="orderBean">
select o.*,p.*,oi.*, o.id 'oid', p.id 'pid', oi.id 'oiid', p.name 'pname'
from order_ o
left join order_item_ oi on o.id =oi.oid
left join product_ p on p.id = oi.pid
</select>
<!-- 定義查詢語句,id指定查詢語句的唯一標識,resultMap指定結(jié)果映射的唯一標識 -->
<select id="getOrder" resultMap="orderBean">
select o.*,p.*,oi.*, o.id 'oid', p.id 'pid', oi.id 'oiid', p.name 'pname'
from order_ o
left join order_item_ oi on o.id =oi.oid
left join product_ p on p.id = oi.pid
where o.id = #{id}
</select>
</mapper>
OrderItem.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文件,指定命名空間為com.how2java.pojo -->
<mapper namespace="com.how2java.pojo">
<!-- 定義插入語句,id指定插入語句的唯一標識,parameterType指定傳入?yún)?shù)的Java類型 -->
<insert id="addOrderItem" parameterType="OrderItem">
insert into order_item_
values(null,#{order.id},#{product.id},#{number})
</insert>
<!-- 定義刪除語句,id指定刪除語句的唯一標識,parameterType指定傳入?yún)?shù)的Java類型 -->
<insert id="deleteOrderItem" parameterType="OrderItem">
delete from order_item_
where oid = #{order.id} and pid = #{product.id}
</insert>
</mapper>
Product.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文件,指定命名空間為com.how2java.pojo -->
<mapper namespace="com.how2java.pojo">
<!-- 定義結(jié)果映射,type指定結(jié)果映射的Java類型,id指定結(jié)果映射的唯一標識 -->
<resultMap type="Product" id="productBean">
<!-- 定義主鍵,column指定數(shù)據(jù)庫表中的列名,property指定Java對象中的屬性名 -->
<id column="pid" property="id" />
<!-- 定義普通屬性,column指定數(shù)據(jù)庫表中的列名,property指定Java對象中的屬性名 -->
<result column="pname" property="name" />
<result column="price" property="price" />
<!-- 定義多對一關(guān)系,property指定Java主對象中的關(guān)聯(lián)對象屬性名,javaType指定關(guān)聯(lián)對象的Java類型 -->
<association property="category" javaType="Category">
<!-- 定義關(guān)聯(lián)對象的主鍵,column指定數(shù)據(jù)庫表中的列名,property指定Java對象中的屬性名 -->
<id column="cid" property="id"/>
<!-- 定義關(guān)聯(lián)對象的普通屬性,column指定數(shù)據(jù)庫表中的列名,property指定Java對象中的屬性名 -->
<result column="cname" property="name"/>
</association>
</resultMap>
<!-- 定義查詢語句,id指定查詢語句的唯一標識,resultMap指定結(jié)果映射的唯一標識 -->
<select id="listProduct" resultMap="productBean">
select c.*, p.*, c.id 'cid', p.id 'pid', c.name 'cname', p.name 'pname'
from category_ c
left join product_ p on c.id = p.cid
</select>
<!-- 定義查詢語句,id指定查詢語句的唯一標識,resultMap指定結(jié)果映射的唯一標識 -->
<select id="getProduct" resultMap="productBean">
select c.*, p.*, c.id 'cid', p.id 'pid', c.name 'cname', p.name 'pname'
from category_ c
left join product_ p on c.id = p.cid
where p.id = #{id}
</select>
</mapper>
(5)測試類:
TestMyBatis.java:
// 導入需要的類
package com.how2java;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.how2java.pojo.Order;
import com.how2java.pojo.OrderItem;
import com.how2java.pojo.Product;
public class TestMybatis {
public static void main(String[] args) throws IOException {
// 加載MyBatis配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 打開一個新的SqlSession
SqlSession session = sqlSessionFactory.openSession();
// 調(diào)用listOrder方法
listOrder(session);
// 提交事務并關(guān)閉SqlSession
session.commit();
session.close();
}
private static void listOrder(SqlSession session) {
// 調(diào)用selectList方法,查詢所有訂單
List<Order> os = session.selectList("listOrder");
for (Order o : os) {
// 打印訂單編號
System.out.println(o.getCode());
// 獲取訂單項列表
List<OrderItem> ois= o.getOrderItems();
for (OrderItem oi : ois) {
// 打印訂單項信息,包括商品名稱、價格和數(shù)量
System.out.format("\t%s\t%f\t%d%n", oi.getProduct().getName(),oi.getProduct().getPrice(),oi.getNumber());
}
}
}
}
(6)運行查看效果:
運行TestMyBatis.java
理解多對多后,就可以很容易地理解一對多、多對一、一對一了,因為多對多 便是由它們構(gòu)成的。
1.3 動態(tài)SQL:
(1)概述:
在 MyBatis 的高級映射中,動態(tài) SQL 是一種根據(jù)不同條件生成不同 SQL 語句的技術(shù)。它可以根據(jù)條件判斷、循環(huán)等動態(tài)生成 SQL 語句,從而使 SQL 語句更加靈活、可復用和易于維護。
動態(tài) SQL 主要有以下幾種形式:
- if 判斷語句:根據(jù)條件判斷是否添加 SQL 片段。
例如,在查詢商品信息時,如果有商品名稱的查詢條件,則添加一個 WHERE 子句:
<select id="listProductByName" resultType="Product">
SELECT * FROM product
<where>
<if test="name != null">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
</where>
</select>
- choose 語句:根據(jù)條件選擇不同的 SQL 片段。
例如,在查詢商品信息時,如果有商品名稱和商品分類兩個查詢條件,可以使用 choose 語句根據(jù)條件選擇不同的 SQL 片段:
<select id="listProduct" resultType="Product">
SELECT * FROM product
<where>
<choose>
<when test="name != null">
AND name LIKE CONCAT('%', #{name}, '%')
</when>
<when test="category != null">
AND category = #{category}
</when>
<otherwise>
AND 1=1
</otherwise>
</choose>
</where>
</select>
- foreach 循環(huán)語句:根據(jù)集合循環(huán)生成 SQL 片段。
例如,在批量插入商品信息時,可以使用 foreach 循環(huán)語句根據(jù)集合循環(huán)生成插入 SQL 語句:
<insert id="insertProducts" parameterType="List">
INSERT INTO product(name, category, price)
VALUES
<foreach collection="list" item="product" separator=",">
(#{product.name}, #{product.category}, #{product.price})
</foreach>
</insert>
通過動態(tài) SQL 技術(shù),可以使 SQL 語句更加靈活、可復用和易于維護,從而提高開發(fā)效率和代碼質(zhì)量。
(2)先知
OGNL表達式:
OGNL(Object-Graph Navigation Language)是一種表達式語言,用于訪問 Java 對象的屬性、方法和索引等數(shù)據(jù)。它可以在 Java Web 開發(fā)中用于 JSP 頁面、Struts2 框架、Spring框架等多個場景中,用于處理表單數(shù)據(jù)、訪問數(shù)據(jù)庫、控制頁面顯示等任務。
OGNL 表達式的語法類似于 Java 語言,支持訪問對象屬性、調(diào)用對象方法、訪問數(shù)組和集合等操作。例如,以下是一些 OGNL 表達式的示例:
- 訪問對象屬性:
user.name
、product.price
等。 - 調(diào)用對象方法:
user.getName()
、product.getPrice()
等。 - 訪問數(shù)組和集合:
array[0]
、list[1]
等。
在 MyBatis 中,OGNL 表達式常用于映射文件中的SQL 語句中的條件判斷、動態(tài) SQL 語句的拼接等場景中。例如,在 MyBatis 映射文件中,可以使用 <if>
標簽中的 test
屬性指定一個 OGNL 表達式,用于判斷條件是否成立,從而決定是否添加 SQL 語句的某些部分。例如:
<select id="listProduct" resultType="Product">
SELECT * FROM product
<where>
<if test="name != null">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
</where>
</select>
在這個例子中,<if>
標簽的 test
屬性指定了一個 OGNL 表達式 name != null
,用于判斷傳入的參數(shù) name
是否為 null,從而決定是否添加 SQL 語句中的 where
子句。
(2)以foreach為例進行展示:
映射文件——Product.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 定義了DTD文件的位置和版本 -->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 定義了命名空間 -->
<mapper namespace="com.how2java.pojo">
<!-- 定義了查詢語句,使用了ID作為查詢語句的標識,resultType指定了查詢結(jié)果的類型 -->
<select id="listProduct" resultType="Product">
<!-- 查詢語句,查詢了product_表中的所有列,并且只返回ID列的值在一個指定列表中的行 -->
SELECT * FROM product_
WHERE ID in
<!-- 動態(tài)生成參數(shù)列表,參數(shù)列表就是指定列表中的元素 -->
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
<!-- 每個元素都會被替換成#{item},其中item是一個變量名,用于引用列表中的每一個元素 -->
#{item}
</foreach>
</select>
</mapper>
測試類——TestMybatis.java:
package com.how2java;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.how2java.pojo.Product;
public class TestMybatis {
public static void main(String[] args) throws IOException {
// 加載 MyBatis 配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 構(gòu)建 SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 打開一個新的 SqlSession
SqlSession session = sqlSessionFactory.openSession();
// 構(gòu)建一個 id 集合,用于查詢指定 id 的產(chǎn)品
List<Integer> ids = new ArrayList();
ids.add(1);
ids.add(3);
ids.add(5);
// 執(zhí)行查詢操作,返回查詢結(jié)果
List<Product> ps = session.selectList("listProduct",ids);
// 遍歷查詢結(jié)果并輸出
for (Product p : ps) {
System.out.println(p);
}
// 提交事務
session.commit();
// 關(guān)閉 SqlSession
session.close();
}
}
運行效果:
2.分頁:
MyBatis中的分頁是指將查詢結(jié)果按照指定的大小分為多個部分,每次只查詢其中的一部分,以減少查詢的數(shù)據(jù)量和提高查詢效率。實現(xiàn)分頁的方式有多種,其中比較常用的方式是使用 SQL 語句中的
limit
關(guān)鍵字,通過設置limit
子句的起始位置和返回數(shù)據(jù)的數(shù)量來實現(xiàn)分頁。
例如,下面的 SQL 語句將查詢結(jié)果按照 id 排序,并返回第 10 條到第 20 條記錄:
select * from my_table order by id limit 10, 10;
在 MyBatis 中,實現(xiàn)分頁需要在映射文件中定義一個查詢語句,并通過參數(shù)傳遞起始位置和返回數(shù)據(jù)的數(shù)量。例如,在上述代碼中,可以通過添加以下代碼來實現(xiàn)分頁:
<select id="listProduct" parameterType="map" resultType="Product">
select * from product
where id in
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
order by id
limit #{start}, #{count}
</select>
其中,#{start}
和 #{count}
分別表示起始位置和返回數(shù)據(jù)的數(shù)量,可以通過參數(shù)傳遞。例如,在 Java 代碼中,可以構(gòu)造一個 Map 對象,將起始位置和返回數(shù)據(jù)的數(shù)量作為鍵值對存入其中,并作為參數(shù)傳遞給查詢語句:
Map<String, Object> params = new HashMap<>();
params.put("ids", ids);
params.put("start", 0);
params.put("count", 10);
List<Product> ps = session.selectList("listProduct", params);
這樣,就可以查詢出 id 在指定集合中的商品列表的前 10 條記錄。
對于第二份代碼,如果要實現(xiàn)分頁,只需要在查詢語句中添加 limit
子句,并通過參數(shù)傳遞起始位置和返回數(shù)據(jù)的數(shù)量即可。例如,在查詢所有分類的語句中,可以添加以下代碼來實現(xiàn)分頁:
<select id="listCategory" resultType="Category">
select * from category_
<if test="start != null and count != null">
limit #{start}, #{count}
</if>
</select>
然后,在 Java 代碼中,可以構(gòu)造一個 Map 對象,將起始位置和返回數(shù)據(jù)的數(shù)量作為鍵值對存入其中,并作為參數(shù)傳遞給查詢語句:文章來源:http://www.zghlxwxcb.cn/news/detail-459521.html
Map<String, Object> params = new HashMap<>();
params.put("start", 0);
params.put("count", 10);
List<Category> cs = session.selectList("listCategory", params);
how2j分頁章節(jié)運行截圖:
文章來源地址http://www.zghlxwxcb.cn/news/detail-459521.html
到了這里,關(guān)于Web應用技術(shù)(第十三周/第二次練習/7h)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!