Web应用技术(第十三周/第二次练习/7h)

这篇具有很好参考价值的文章主要介绍了Web应用技术(第十三周/第二次练习/7h)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.MyBatis高级映射:

MyBatis的高级映射是指在MyBatis中使用更加灵活和强大的技术来实现数据持久化和对象关系映射的方式。高级映射包括以下几种技术:

  1. 动态SQL:可以根据不同的条件动态生成SQL语句。

  2. 嵌套查询:可以在一个查询语句中嵌套另一个查询语句,实现复杂的查询操作。

  3. 延迟加载:可以在需要时才去加载关联对象,减少数据库的访问次数,提高性能。

  4. 自动映射:可以根据数据库表和Java类的命名规则自动映射属性和字段。

  5. 缓存:可以将查询结果缓存到内存中,提高查询性能。

  6. 批量操作:可以将多个操作一起提交到数据库,提高数据库操作效率。

这些高级映射技术可以让开发人员更加方便地使用MyBatis来实现数据持久化和对象关系映射,提高开发效率和系统性能。

1.1 相关XML标签及其属性:

(1)mapper标签:

MyBatis中的mapper标签是用来定义SQL语句和映射关系的,它可以将SQL语句和Java方法绑定起来,实现数据的持久化和对象关系映射。在使用MyBatis时,通常会将mapper标签定义在XML文件中,然后通过SqlSessionFactory加载和解析XML文件,创建SqlSession对象进行数据库操作。

具体来说,mapper标签包含了一组SQL语句和映射关系,可以通过namespace属性来指定命名空间,通过id属性来指定SQL语句的唯一标识符。在mapper标签内部,可以使用select、insert、update、delete等标签来定义具体的SQL语句和参数映射关系。例如:

<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语句和对应的参数映射关系。
其中,
select标签定义了一个id为getUserById的SQL语句,使用了一个int类型的参数id和一个com.example.User类型的返回值。
insert标签定义了一个id为insertUser的SQL语句,使用了一个com.example.User类型的参数,并且开启了自动生成主键的功能。
update标签定义了一个id为updateUser的SQL语句,使用了一个com.example.User类型的参数。
delete标签定义了一个id为deleteUser的SQL语句,使用了一个int类型的参数id。


(2)DOCTYPE标签:

MyBatis配置文件中的DOCTYPE声明,它指定了MyBatis配置文件的DTD(Document Type Definition),用于验证和解析XML文件的结构和内容。它的作用是告诉XML解析器使用指定的DTD来验证和解析XML文件,确保XML文件的结构和内容符合规范。如果XML文件的结构和内容不符合DTD的规范,解析器会报错并停止解析。它不是必须的,但建议在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文件的结构和内容符合规范。configuration标签是MyBatis配置文件的根元素,包含了environments和mappers两个子元素,用于配置数据库环境和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接口来声明映射关系。

具体来说,标签可以包含以下两个子标签:

  • mapper:用于指定映射文件的位置或通过Java接口来声明映射关系。可以使用resource、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>标签指定了三种方式来声明映射关系:
通过resource属性指定了一个映射文件com/example/UserMapper.xml;
通过class属性指定了一个 Java接口com.example.OrderMapper;
通过package标签指定了一个自动扫描的包com.example.mapper。
这样,在MyBatis启动时,会自动加载并解析这些映射文件或Java接口,建立映射关系,以便在后续的数据库操作中使用。

需要注意的是,标签可以定义在MyBatis配置文件中,也可以定义在映射文件中。如果定义在MyBatis配置文件中,则可以在所有映射文件中使用;如果定义在映射文件中,则只能在当前映射文件中使用。


(5)resultMap标签:

MyBatis 中,resultMap 是一个映射结果集的标签,用于将 SQL 查询结果映射到 Java 对象中。resultMap标签可以定义在xml映射文件中,也可以定义在 Java 接口或抽象类中。

resultMap 标签有以下属性:

  • id:标识 resultMap 的唯一标识符,必须指定。
  • type:指定映射结果集的返回类型,可以是 Java 类型或别名,必须指定。
  • extends:指定继承的 resultMap 的 id,可选属性。

resultMap 标签有以下子标签:

  • id:用于映射主键字段。
  • result:用于映射普通字段。
  • association:用于关联另一个 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 查询结果映射到 User 类型的对象中。
其中,
id 子标签映射主键字段,
result 子标签映射普通字段,
association 子标签映射关联对象,
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是一种结果映射的方式,用于建立两个Java对象之间的多对一关系。当查询结果中包含了关联对象的信息时,可以使用association将关联对象映射到主对象的属性上。

association有以下常用属性:

  • property:指定主对象中的关联对象属性名。
  • javaType:指定关联对象的Java类型。
  • columnPrefix:指定关联对象在查询结果中的列名前缀。
  • resultMap:指定关联对象的结果映射。

举个例子,假设有两个Java对象Product和Category,它们之间是多对一关系,即一个商品属于一个分类,一个分类下有多个商品。那么可以定义如下的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。
当查询结果中包含了Category对象的信息时,MyBatis会自动将Category对象映射到Product对象的category属性上。
其中,id和result分别定义了Category对象的主键和普通属性的映射关系。这样,在查询Product对象时,就可以同时获取到关联的Category对象的信息了。

简单来说,association用于声明外键。


(7)collection:

MyBatis中,collection是一种结果映射的方式,用于建立两个Java对象之间的一对多关系。当查询结果中包含了关联对象的集合信息时,可以使用collection将关联对象集合映射到主对象的属性上。

collection有以下常用属性:

  • property:指定主对象中的关联对象集合属性名。
  • ofType:指定关联对象集合中的元素类型。
  • columnPrefix:指定关联对象在查询结果中的列名前缀。
  • resultMap:指定关联对象的结果映射。

举个例子,假设有两个Java对象Category和Product,它们之间是一对多关系,即一个分类下有多个商品。那么可以定义如下的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。
当查询结果中包含了Category对象和其关联的Product对象集合时,
MyBatis会自动将Product对象集合映射到Category对象的products属性上。
其中,id和result分别定义了Product对象的主键和普通属性的映射关系。
这样,在查询Category对象时,就可以同时获取到其关联的Product对象集合信息了。


1.2 多对多:

(1)先知:

how2j上给定地是一个商品-商品种类-订单项-订单的模型
这里简单解释一下订单和订单项目:

  • 订单是指客户向商家提交的购买请求,包含了购买的商品、数量、价格、支付方式、收货地址等信息。一般来说,订单会被分配一个唯一的订单号,以便于商家和客户对订单进行跟踪和管理。

  • 订单项是指订单中的一个商品条目,包含了购买的商品、数量、价格等信息。一个订单可以包含多个订单项,每个订单项对应一个商品。因此,订单项是订单的组成部分,用于记录订单中每个商品的详细信息。

实现一对多,是通过collection标签实现的,
实现多对一,是通过association标签实现的,
那么,实现多对多就需要collection和association一起使用,更具体的说,是嵌套使用,即“嵌套结果映射”。

下方是我们希望在控制台呈现的内容与结构

code000A
	product a	88.879997	100
	product b	88.879997	101
	product c	88.879997	102

进一步抽象,得到

订单号—订单项—商品,
故我们需要配置的映射文件的结构应该如下图红色指示线所示

Web应用技术(第十三周/第二次练习/7h)

因此how2j上提供的映射配置文件中的内容是有很多无用部分的,这些部分是为前两节“一对多”和“多对一“服务的,比如说Category.xml的association标签及其包含内容,在多对多映射中,我们根本不需要product去关联category,因此这些无用标签删去后也可正常运行测试类,为了不增加工作量,我没有删除,但是测试了几个,确实是可以删除并正常运行的,这就说明我的理解没有出错。

Web应用技术(第十三周/第二次练习/7h)

文件目录结构如图所示:
Web应用技术(第十三周/第二次练习/7h)

(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;
	// 订单项数量
	private int number;
	// 订单
	private Order order;
	// 商品
	private Product product;
	
	// 获取订单项id
	public int getId() {
		return id;
	}
	
	// 设置订单项id
	public void setId(int id) {
		this.id = id;
	}
	
	// 获取订单项数量
	public int getNumber() {
		return number;
	}
	
	// 设置订单项数量
	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; // 产品的唯一标识符,用于识别不同的产品
	private String name; // 产品的名称,用于描述产品的特征
	private float price; // 产品的价格,用于表示产品的价值
	private Category category; // 产品所属的类别,用于分类管理产品

	public Category getCategory() { // 获取产品所属的类别
		return category;
	}

	public void setCategory(Category category) { // 设置产品所属的类别
		this.category = category;
	}

	public int getId() { // 获取产品的唯一标识符
		return id;
	}

	public void setId(int id) { // 设置产品的唯一标识符
		this.id = id;
	}

	public String getName() { // 获取产品的名称
		return name;
	}

	public void setName(String name) { // 设置产品的名称
		this.name = name;
	}

	public float getPrice() { // 获取产品的价格
		return price;
	}

	public void setPrice(float price) { // 设置产品的价格
		this.price = price;
	}

	@Override
	public String toString() { // 重写toString方法,用于打印产品信息
		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 的语法规范。
-->
<configuration>  
	<!-- 声明类型别名,用于简化 Java 类型的命名,方便在 XML 中引用。 -->
	<typeAliases>
	  <package name="com.how2java.pojo"/>
	</typeAliases>
    <!-- 声明环境,用于定义 MyBatis 的运行环境,包括事务管理器和数据源等。 -->
    <environments default="development">
        <environment id="development">
            <!-- 声明事务管理器类型,用于管理数据库事务,包括开启、提交、回滚等操作。 -->
            <transactionManager type="JDBC"/>
            <!-- 声明数据源类型,用于连接数据库,包括数据库驱动、URL、用户名和密码等信息。 -->
            <dataSource type="POOLED">
                <!-- 数据库驱动 -->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!-- 数据库连接URL -->
                <property name="url" value="jdbc:mysql://localhost:3306/how2java?characterEncoding=UTF-8"/>
                <!-- 数据库用户名 -->
                <property name="username" value="root"/>
                <!-- 数据库密码 -->
                <property name="password" value="admin"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 声明映射器,用于定义数据库操作的 SQL 语句和映射关系。 -->
    <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,用于将查询结果映射到 Category 对象中 -->
    <resultMap type="Category" id="categoryBean">
        <!-- id 标签用于指定对象的主键属性,
        column 属性指定了查询结果中的列名,
        property 属性指定了对象中的属性名 -->
        <id column="cid" property="id" />
        <!-- result 标签用于指定对象的其他属性,
        column 和 property 属性的含义与 id 标签相同 -->
        <result column="cname" property="name" />
        
        <!-- 一对多的关系,
        collection 标签用于指定集合属性的名称和类型 -->
        <!-- property 属性指定了主对象集合属性的名称,
        	 ofType 属性指定了关联对象集合中元素的类型 -->
        <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>
    
    <!-- 关联查询分类和产品表 -->
    <!-- id 属性指定了 SQL 语句的唯一标识符 -->
    <!-- resultMap 属性指定了查询结果映射的 resultMap 的唯一标识符 -->
    <select id="listCategory" resultMap="categoryBean">
        <!-- 使用 left join 连接分类表和产品表 -->
        <!-- c.*, p.* 表示查询分类表和产品表的全部列 -->
        <!-- 别名语法用于将查询结果中的列映射到对象的属性中 -->
        <!-- column 属性指定了查询结果中的列名,'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的插入操作,参数类型为Category -->
	    <insert id="addCategory" parameterType="Category" >
	        insert into category_ ( name ) values (#{name})    
	    </insert>
	    
	    <!-- 定义一个名为deleteCategory的删除操作,参数类型为Category -->
	    <delete id="deleteCategory" parameterType="Category" >
	        delete from category_ where id= #{id}   
	    </delete>
	    
	    <!-- 定义一个名为getCategory的查询操作,参数类型为int,结果类型为Category -->
	    <select id="getCategory" parameterType="_int" resultType="Category">
	        select * from   category_  where id= #{id}    
	    </select>

	    <!-- 定义一个名为updateCategory的更新操作,参数类型为Category -->
	    <update id="updateCategory" parameterType="Category" >
	        update category_ set name=#{name} where id=#{id}    
	    </update>
	    
	    <!-- 定义一个名为listCategory的查询操作,结果类型为Category -->
	    <select id="listCategory1" resultType="Category">
	        select * from   category_      
	    </select>	
	    
	    <!-- 定义一个名为listCategoryByName的查询操作,参数类型为string,结果类型为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">
	
	<!-- 定义结果映射,type指定结果映射的Java类型,id指定结果映射的唯一标识 -->
	<resultMap type="Order" id="orderBean">
		
		<!-- 定义主键,column指定数据库表中的列名,property指定Java对象中的属性名 -->
		<id column="oid" property="id" />
		
		<!-- 定义普通属性,column指定数据库表中的列名,property指定Java对象中的属性名 -->
		<result column="code" property="code" />
		
		<!-- 定义集合属性,property指定Java主对象中的集合属性名,ofType指定关联对象集合元素的Java类型 -->
		<!-- 一对多 -->
		<collection property="orderItems" ofType="OrderItem">
			
			<!-- 定义集合元素的主键,column指定数据库表中的列名,property指定Java对象中的属性名 -->
			<id column="oiid" property="id" />
			
			<!-- 定义集合元素的普通属性,column指定数据库表中的列名,property指定Java对象中的属性名 -->
			<result column="number" property="number" />
			
			<!-- 定义集合元素的关联对象,property指定Java主对象中的对象属性名,javaType指定关联对象的Java类型 -->
		<!-- 多对1 -->
			<association property="product" javaType="Product">
				
				<!-- 定义关联对象的主键,column指定数据库表中的列名,property指定Java对象中的属性名 -->
				<id column="pid" property="id"/>
				
				<!-- 定义关联对象的普通属性,column指定数据库表中的列名,property指定Java对象中的属性名 -->
				<result column="pname" property="name"/>
				<result column="price" property="price"/>
			</association>				
		</collection>
	</resultMap>
	
	<!-- 定义查询语句,id指定查询语句的唯一标识,resultMap指定结果映射的唯一标识 -->
	<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指定结果映射的唯一标识 -->
	<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指定传入参数的Java类型 -->
	<insert id="addOrderItem" parameterType="OrderItem">
		insert into order_item_ 
			values(null,#{order.id},#{product.id},#{number})
	</insert>    
	
	<!-- 定义删除语句,id指定删除语句的唯一标识,parameterType指定传入参数的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">
	
	<!-- 定义结果映射,type指定结果映射的Java类型,id指定结果映射的唯一标识 -->
	<resultMap type="Product" id="productBean">
		
		<!-- 定义主键,column指定数据库表中的列名,property指定Java对象中的属性名 -->
		<id column="pid" property="id" />
		
		<!-- 定义普通属性,column指定数据库表中的列名,property指定Java对象中的属性名 -->
		<result column="pname" property="name" />
		<result column="price" property="price" />
	
		<!-- 定义多对一关系,property指定Java主对象中的关联对象属性名,javaType指定关联对象的Java类型 -->
		<association property="category" javaType="Category">
			
			<!-- 定义关联对象的主键,column指定数据库表中的列名,property指定Java对象中的属性名 -->
			<id column="cid" property="id"/>
			
			<!-- 定义关联对象的普通属性,column指定数据库表中的列名,property指定Java对象中的属性名 -->
			<result column="cname" property="name"/>
		</association>
	</resultMap>

	<!-- 定义查询语句,id指定查询语句的唯一标识,resultMap指定结果映射的唯一标识 -->
	<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指定结果映射的唯一标识 -->
	<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();
 
        // 调用listOrder方法
        listOrder(session);
 
        // 提交事务并关闭SqlSession
        session.commit();
        session.close();
 
    }
 
    private static void listOrder(SqlSession session) {
        // 调用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) {
                // 打印订单项信息,包括商品名称、价格和数量
                System.out.format("\t%s\t%f\t%d%n", oi.getProduct().getName(),oi.getProduct().getPrice(),oi.getNumber());
            }
        }
    }
}

(6)运行查看效果:

运行TestMyBatis.java

Web应用技术(第十三周/第二次练习/7h)

理解多对多后,就可以很容易地理解一对多、多对一、一对一了,因为多对多 便是由它们构成的。

1.3 动态SQL:

(1)概述:

在 MyBatis 的高级映射中,动态 SQL 是一种根据不同条件生成不同 SQL 语句的技术。它可以根据条件判断循环动态生成 SQL 语句,从而使 SQL 语句更加灵活、可复用和易于维护。

动态 SQL 主要有以下几种形式:

  1. if 判断语句:根据条件判断是否添加 SQL 片段。

例如,在查询商品信息时,如果有商品名称的查询条件,则添加一个 WHERE 子句:

<select id="listProductByName" resultType="Product">
    SELECT * FROM product
    <where>
        <if test="name != null">
            AND name LIKE CONCAT('%', #{name}, '%')
        </if>
    </where>
</select>
  1. choose 语句:根据条件选择不同的 SQL 片段。

例如,在查询商品信息时,如果有商品名称和商品分类两个查询条件,可以使用 choose 语句根据条件选择不同的 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>
  1. foreach 循环语句:根据集合循环生成 SQL 片段。

例如,在批量插入商品信息时,可以使用 foreach 循环语句根据集合循环生成插入 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>

通过动态 SQL 技术,可以使 SQL 语句更加灵活、可复用和易于维护,从而提高开发效率和代码质量。


(2)先知

OGNL表达式:

OGNL(Object-Graph Navigation Language)是一种表达式语言,用于访问 Java 对象的属性、方法和索引等数据。它可以在 Java Web 开发中用于 JSP 页面、Struts2 框架、Spring框架等多个场景中,用于处理表单数据、访问数据库、控制页面显示等任务。

OGNL 表达式的语法类似于 Java 语言,支持访问对象属性、调用对象方法、访问数组和集合等操作。例如,以下是一些 OGNL 表达式的示例:

  • 访问对象属性:user.nameproduct.price 等。
  • 调用对象方法:user.getName()product.getPrice() 等。
  • 访问数组和集合:array[0]list[1] 等。

在 MyBatis 中,OGNL 表达式常用于映射文件中的SQL 语句中的条件判断、动态 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,用于判断传入的参数 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指定了查询结果的类型 -->
	<select id="listProduct" resultType="Product">
		<!-- 查询语句,查询了product_表中的所有列,并且只返回ID列的值在一个指定列表中的行 -->
		SELECT * FROM product_ 
		WHERE ID in
		<!-- 动态生成参数列表,参数列表就是指定列表中的元素 -->
		<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);
        // 构建 SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 打开一个新的 SqlSession
        SqlSession session = sqlSessionFactory.openSession();

        // 构建一个 id 集合,用于查询指定 id 的产品
        List<Integer> ids = new ArrayList();
        ids.add(1);
        ids.add(3);
        ids.add(5);

        // 执行查询操作,返回查询结果
        List<Product> ps = session.selectList("listProduct",ids);
        // 遍历查询结果并输出
        for (Product p : ps) {
            System.out.println(p);
        }

        // 提交事务
        session.commit();
        // 关闭 SqlSession
        session.close();

    }
}


运行效果:

Web应用技术(第十三周/第二次练习/7h)

2.分页:

MyBatis中的分页是指将查询结果按照指定的大小分为多个部分,每次只查询其中的一部分,以减少查询的数据量和提高查询效率。实现分页的方式有多种,其中比较常用的方式是使用 SQL 语句中的 limit 关键字,通过设置 limit 子句的起始位置返回数据的数量来实现分页。

例如,下面的 SQL 语句将查询结果按照 id 排序,并返回第 10 条到第 20 条记录:

select * from my_table order by id limit 10, 10;

在 MyBatis 中,实现分页需要在映射文件中定义一个查询语句,并通过参数传递起始位置和返回数据的数量。例如,在上述代码中,可以通过添加以下代码来实现分页:

<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} 分别表示起始位置返回数据的数量,可以通过参数传递。例如,在 Java 代码中,可以构造一个 Map 对象,将起始位置和返回数据的数量作为键值对存入其中,并作为参数传递给查询语句:

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 条记录。

对于第二份代码,如果要实现分页,只需要在查询语句中添加 limit 子句,并通过参数传递起始位置和返回数据的数量即可。例如,在查询所有分类的语句中,可以添加以下代码来实现分页:

<select id="listCategory" resultType="Category">
    select * from category_
    <if test="start != null and count != null">
        limit #{start}, #{count}
    </if>
</select>

然后,在 Java 代码中,可以构造一个 Map 对象,将起始位置和返回数据的数量作为键值对存入其中,并作为参数传递给查询语句:

Map<String, Object> params = new HashMap<>();
params.put("start", 0);
params.put("count", 10);
List<Category> cs = session.selectList("listCategory", params);

how2j分页章节运行截图:

Web应用技术(第十三周/第二次练习/7h)文章来源地址https://www.toymoban.com/news/detail-459521.html

到了这里,关于Web应用技术(第十三周/第二次练习/7h)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 四、web应用程序技术——HTTP

      HTTP(HyperText Transfer Protocol,超文本传输协议)是访问万维网使用的核心通信协议,也是今天web应用程序使用的通讯协议。   HTTP使用一种基于消息的模型: 客户端发出一条请求消息,而后由服务端返回一条响应消息 。   所有HTTP消息(请求与响应)中都包含 一个或

    2024年02月13日
    浏览(40)
  • 专项技能训练五《云计算网络技术与应用》实训5-1:OpenvSwitch环境安装及常用操作练习

    实验前准备:编辑虚拟机网络配置,使VMnet8处在192.168.10.0网段,VMnet1处在192.168.1.0网段。 1. 使用VMware安装CentOS 7虚拟机,安装时需添加多一张网卡,该网卡为自定义-VMnet1.并且记得开启CPU虚拟化,将其命名为“OVS1”。 2. 安装完虚拟机后,进入虚拟机,修改网络配置(onboot改为

    2024年04月09日
    浏览(89)
  • 探索web技术与低代码开发的融合应用

    随着物联网、云计算和人工智能等技术的迅猛发展,现代软件开发正面临着日益增长的需求和复杂性。为了应对这一挑战,一种被称为低代码开发的快速、可视化开发方法逐渐崭露头角。本文将探讨低代码开发与web技术的融合应用,以及这种趋势对软件开发生态系统的影响。

    2024年01月20日
    浏览(53)
  • 如何在 2022 年为 Web 应用程序选择技术堆栈

    选择最佳的 Web 应用程序堆栈并非易事:它必须在资源和质量方面达到最佳。 Web 应用程序开发所需的质量、成本和时间将取决于您的选择。 这就是为什么选择技术堆栈可能需要比您预期更多的时间。 在本文中,我将帮助您选择最有效的 Web 开发技术栈。 我将解释哪些技术可

    2024年02月01日
    浏览(57)
  • 区块链技术与应用 【全国职业院校技能大赛国赛题目解析】第二套区块链系统部署与运维

    第二套区块链系统部署与运维题目 环境 : ubuntu20 fisco : 2.8.0 docker: 20.10.21 webase-deploy : 1.5.5 mysql: 8.0.34 使用 build_chain.sh 脚本文件进行搭建区块链 ,要求: 四节点,默认配置,单机,docker

    2024年02月08日
    浏览(60)
  • 成都工业学院Web技术基础(WEB)实验四:CSS3布局应用

    写在前面 1、基于2022级计算机大类实验指导书 2、代码仅提供参考,前端变化比较大,按照要求,只能做到像,不能做到一模一样 3、图片和文字仅为示例,需要自行替换 4、如果代码不满足你的要求,请寻求其他的途径 运行环境 window11家庭版 WebStorm 2023.2.2 实验要求、源代码

    2024年02月01日
    浏览(40)
  • 物联网控制原理与技术--基于Matlab/利用MATLAB进行频域分析(伯德图)的应用(超详细/设计/实验/作业/练习)

    (1)熟练掌握运用MATLAB命令绘制控制系统伯德图的方法; (2)了解系统伯德图的一般规律及其频域指标的获取方法; (3)熟练掌握运用伯德图分析控制系统稳定性的方法; 1、Windows 10 2、Matlab 2012a 1. 用MATLAB作伯德图 控制系统工具箱里提供的bode()函数可以直接求取、绘制给

    2024年02月09日
    浏览(28)
  • 保护用户数据隐私:Web3 技术在电商行业中的应用

    电商行业一直是全球经济发展的重要推动力。然而,随着电商行业的不断发展,中心化的支付、物流和数据存储方式逐渐暴露出安全隐患和隐私问题。这时,Web3 技术以其去中心化、安全性和透明性等特点,为电商行业带来了新的解决方案和可能性。 一、Web3 技术在电商支付

    2024年02月13日
    浏览(25)
  • 云计算虚拟化技术与开发-------虚拟化技术应用第二章内容(CPU虚拟机X86要解决的问题、VT-x、VMX、vCPU、EPT、VT-d)

    目录 第二章:虚拟化实现技术架构 CPU虚拟机要解决的问题(x86处理器结构漏洞)及软硬件解决方案 intel VT-x的技术特点,VMX(非根操作)的操作模式及操作流程 vCPU的组成和基本操作 内存虚拟化的地址映射问题 Intel EPT的基本概念及地址转换实现过程 Intel VT-d的技术特点以及

    2024年02月04日
    浏览(36)
  • 提升Web3安全性和用户体验:元事务和加密技术的应用

    在Web3中,去中心化应用程序(DApps)是一种基于区块链技术的应用程序,它们通过智能合约实现透明、安全、去中心化的业务逻辑。然而,DApps的使用门槛比传统的中心化应用程序更高,需要用户具备一定的技术知识,例如安装和使用区块链钱包、交互式智能合约等。 为了解

    2024年02月16日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包