MyBatis框架进阶(二)

MyBatis的关系映射

1.一对多关系映射

本例建立在我的上一篇文章 MyBatis框架入门(一)的基础上,实现一个分类对应多个产品
新创建一个产品表
create table product(
id int NOT NULL AUTO_INCREMENT,
name varchar(30)  DEFAULT NULL,
price float  DEFAULT 0,
cid int ,
PRIMARY KEY (id)
)AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
清空category表和product表,插入新数据
delete from category;
INSERT INTO category VALUES (1,'category1');
INSERT INTO category VALUES (2,'category2');
delete from product;
INSERT INTO product VALUES (1,'product a', 88.88, 1);
INSERT INTO product VALUES (2,'product b', 88.88, 1);
INSERT INTO product VALUES (3,'product c', 88.88, 1);
INSERT INTO product VALUES (4,'product x', 88.88, 2);
INSERT INTO product VALUES (5,'product y', 88.88, 2);
INSERT INTO product VALUES (6,'product z', 88.88, 2);
创建Product实体类
package pojo;
 
public class Product {
    private int id;
    private String name;
    private float price;
    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() {
        return "Product [id=" + id + ", name=" + name + ", price=" + price + "]";
    }
 
}
修改 Category实体类,提供products的集合
    private List<Product> products;

    public List<Product> getProducts() {
        return products;
    }

    public void setProducts(List<Product> products) {
        this.products = products;
    }
暂时 无需Product.xml
修改Category.xml

通过resultMap,进行字段和属性的对应

使用collection进行一对多关系关联,指定表字段名称与对象属性名称的一一对应关系

Category的id 字段 和Product的id字段同名,Mybatis不知道谁是谁的,所以需要通过取别名cid,pid来区分。

name字段同理。

<?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="pojo">
        <resultMap type="Category" id="categoryBean">
            <id column="cid" property="id" />
            <result column="cname" property="name" />
     
            <!-- 一对多的关系 -->
            <!-- property: 指的是集合属性的值, ofType:指的是集合中元素的类型 -->
            <collection property="products" ofType="Product">
                <id column="pid" property="id" />
                <result column="pname" property="name" />
                <result column="price" property="price" />
            </collection>
        </resultMap>
     
        <!-- 关联查询分类和产品表 -->
        <select id="listCategories" resultMap="categoryBean">
            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>    
    </mapper>
在主类中测试one-to-many关系
// 一对多  
List<Category> categories = session.selectList("listCategories");  
for (Category category : categories) {  
    System.out.println(category);  
    List<Product> products = category.getProducts();  
    for (Product product : products) {  
        System.out.println("\t" + product);  
    }  
}
2.多对一关系映射
本例实现多个Product对应一个Category关系映射

修改Product实体类,增加category属性

    private Category category;
     
    public Category getCategory() {
        return category;
    }
    public void setCategory(Category category) {
        this.category = category;
在同一个包中配置Product.xml
使用association 进行多对一关系关联,指定表字段名称与对象属性名称的一一对应关系
<?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="pojo">
        <resultMap type="Product" id="productBean">
            <id column="pid" property="id" />
            <result column="pname" property="name" />
            <result column="price" property="price" />
     
            <!-- 多对一的关系 -->
            <!-- property: 指的是属性名称, javaType:指的是属性的类型 -->
            <association property="category" javaType="Category">
                <id column="cid" property="id"/>
                <result column="cname" property="name"/>
            </association>
        </resultMap>
     
        <!-- 根据id查询Product, 关联将Orders查询出来 -->
        <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>    
    </mapper>
在mybatis-config.xml中增加对于Product.xml的映射
<mapper resource="pojo/Product.xml"/>
在主类中测试many-to-one关系
       // 多对一  
        List<Product> products = session.selectList("listProduct");  
        for (Product product : products) {  
            System.out.println(product + " 对应的分类是 \t " + product.getCategory());  
        }  
3.多对多关系映射
本例实现多个Product对应多个Orders关系映射
要实现多对多关系映射,需要一张中间表,在本例中为 OrderItem

创建orders表和order_item表

create table orders (
  id int(11) NOT NULL AUTO_INCREMENT,
  code varchar(32) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
 
create table order_item(
  id int(11) NOT NULL AUTO_INCREMENT,  
  oid int , 
  pid int ,
  number int ,
  PRIMARY KEY(id)
)AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

插入数据

INSERT INTO orders VALUES (1,'code000A');
INSERT INTO orders VALUES (2,'code000B');
 
INSERT INTO order_item VALUES (null, 1, 1, 100);
INSERT INTO order_item VALUES (null, 1, 2, 100);
INSERT INTO order_item VALUES (null, 1, 3, 100);
INSERT INTO order_item VALUES (null, 2, 2, 100);
INSERT INTO order_item VALUES (null, 2, 3, 100);
INSERT INTO order_item VALUES (null, 2, 4, 100);

创建Orders实体类

package pojo;
 
import java.util.List;
 
public class Orders {
    private int id;
    private String code;
     
    private List<OrderItem> orderItems;
     
    public int getId() {
        return 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实体类

package pojo;
 
public class OrderItem {
    private int id;
    private int number;
    private Orders orders;
    private Product product;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public int getNumber() {
        return number;
    }
    public void setNumber(int number) {
        this.number = number;
    }
    public Order getOrders() {
        return order;
    }
    public void setOrders(Order order) {
        this.order = order;
    }
    public Product getProduct() {
        return product;
    }
    public void setProduct(Product product) {
        this.product = product;
    }
     
}

在同一包中配置Orders.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="pojo">
        <resultMap type="Orders" id="ordersBean">
            <id column="oid" property="id" />
            <result column="code" property="code" />
             
            <collection property="orderItems" ofType="OrderItem">
                <id column="oiid" property="id" />
                <result column="number" property="number" />
                <association property="product" javaType="Product">
                    <id column="pid" property="id"/>
                    <result column="pname" property="name"/>
                    <result column="price" property="price"/>
                </association>                
            </collection>
        </resultMap>
         
        <select id="listOrders" resultMap="ordersBean">
            select o.*,p.*,oi.*, o.id 'oid', p.id 'pid', oi.id 'oiid', p.name 'pname' 
                from orders o 
                left join order_item oi    on o.id =oi.oid 
                left join product p on p.id = oi.pid 
        </select>
             
        <select id="getOrders" resultMap="ordersBean">
            select o.*,p.*,oi.*, o.id 'oid', p.id 'pid', oi.id 'oiid', p.name 'pname' 
                from orders 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 namespace="pojo">
     
        <insert id="addOrderItem" parameterType="OrderItem">
            insert into order_item 
                values(null,#{order.id},#{product.id},#{number})
        </insert>    
        <insert id="deleteOrderItem" parameterType="OrderItem">
            delete from order_item 
                where oid = #{order.id} and pid = #{product.id}
        </insert>    
     
    </mapper>

修改Product.xml,添加getProduct.xml字段

	<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>

在mybatis-config.xml中添加对于Orders.xml和OrderItem的映射

        <mapper resource="pojo/Orders.xml"/>
        <mapper resource="pojo/OrderItem.xml"/>

主类中测试many-to-many关系

public class App {
	public static void main(String[] args) throws IOException {

		InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		SqlSession session = sqlSessionFactory.openSession();

		// 多对多 
		listOrders(session);
		
		addOrderItem(session);

		deleteOrderItem(session);

		session.commit();
		session.close();

		inputStream.close();
	}

	// 查询订单列表
	private static void listOrder(SqlSession session) {
		List<Orders> orders = session.selectList("listOrders");
		for (Orders order : orders) {
			System.out.println(order.getCode());
			List<OrderItem> orderItems = order.getOrderItems();
			for (OrderItem orderItem : orderItems) {
				System.out.format("\t%s\t%f\t%d%n", orderItem.getProduct().getName(), orderItem.getProduct().getPrice(),
						orderItem.getNumber());
			}
		}
	}

	// 建立关系
	private static void addOrderItem(SqlSession session) {
		Orders orders = session.selectOne("getOrders", 1);
		Product product = session.selectOne("getProduct", 6);
		OrderItem orderItem = new OrderItem();
		orderItem.setProduct(product);
		orderItem.setOrders(orders);
		orderItem.setNumber(200);

		session.insert("addOrderItem", orderItem);
	}

	// 删除关系
	private static void deleteOrderItem(SqlSession session) {
		Orders orders = session.selectOne("getOrders", 1);
		Product product = session.selectOne("getProduct", 6);
		OrderItem orderItem = new OrderItem();
		orderItem.setProduct(product);
		orderItem.setOrders(orders);
		session.delete("deleteOrderItem", orderItem);
	}

MyBatis的动态SQL

修改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 namespace="pojo">
		<!-- 如果没有传参数name,那么就查询所有,如果有name参数,那么就进行模糊查询。 -->
	<select id="ifListProduct" resultType="Product">
		select * from product
		<if test="name != null">
			where name like concat('%', #{name}, '%')
		</if>
	</select>

	<!-- <where>标签会进行自动判断。如果任何条件都不成立,那么就在sql语句里就不会出现where关键字。如果有任何条件成立,会自动去掉多出来的 
		and 或者 or。 -->
	<select id="whereListProduct" resultType="Product">
		select * from product
		<where>
			<if test="name != null">
				and name like concat('%", #{name}", '%')
			</if>
			<if test="price != null and price != 0">
				and price > #{price}
			</if>
		</where>
	</select>

	<!-- 与where标签类似的,在update语句里也会碰到多个字段相关的问题。 在这种情况下,就可以使用set标签 -->
	<update id="setUpdateProduct" parameterType="Product">
		update product
		<set>
			<if test="name != null">name = #{name},</if>
			<if test="price != null">price = #{price}</if>
		</set>
		where id = #{id}
	</update>

	<!-- trim标签trim 用来定制想要的功能,将上面两个标签替换成trim -->
	<select id="trimlistProduct" resultType="Product">
		select * from product
		<trim prefix="WHERE" prefixOverrides="AND |OR ">
			<if test="name!=null">
				and name like concat('%',#{name},'%')
			</if>
			<if test="trimprice!=null and price!=0">
				and price > #{price}
			</if>
		</trim>
	</select>

	<update id="updateProduct" parameterType="Product">
		update product
		<trim prefix="SET" suffixOverrides=",">
			<if test="name != null">name=#{name},</if>
			<if test="price != null">price=#{price}</if>
		</trim>
		where id=#{id}
	</update>

	<!-- Mybatis里面没有else标签,但是可以使用when otherwise标签来达到这样的效果。 -->
	<select id="chooseListProduct" resultType="Product">
		SELECT * FROM product
		<where>
			<choose>
				<when test="name != null">
					and name like concat('%',#{name},'%')
				</when>
				<when test="price !=null and price != 0">
					and price > #{price}
				</when>
				<otherwise>
					and id >1
				</otherwise>
			</choose>
		</where>
	</select>

	<!-- foreach标签通常用于in 这样的语法里,如例,如图查询出id等于1,3,5的数据出来。 -->
	<select id="foreachListProduct" resultType="Product">
		select * from product
		where id in
		<foreach item="item" index="index" collection="list" open="("
			separator="," close=")">
			#{item}
		</foreach>
	</select>

	<!-- bind标签就像是再做一次字符串拼接,方便后续使用。如本例,在模糊查询的基础上,把模糊查询改为bind标签。 --> 
	<select id="bindListProductByName" resultType="Product">
		<bind name="likename" value="'%' + name + '%'" />
		select * from product where name like #{likename}
	</select>
</mapper>

在主类中测试动态SQL功能

public class App {
	public static void main(String[] args) throws IOException {

		InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		SqlSession session = sqlSessionFactory.openSession();

		// if标签
		System.out.println("查询所有的");
		List<Product> products = session.selectList("ifListProduct");
		for (Product product : products) {
			System.out.println(product);
		}

		System.out.println("模糊查询");
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("name", "a");
		List<Product> products2 = session.selectList("ifListProduct", map);
		for (Product product : products2) {
			System.out.println(product);
		}

		// where标签
		System.out.println("多条件查询");
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("price", "10");
		List<Product> products = session.selectList("whereListProduct", map);
		for (Product product : products) {
			System.out.println(product);
		}

		// set标签
		Product product = new Product();
		product.setId(6);
		product.setName("product zz");
		product.setPrice(99.99f);
		session.update("setUpdateProduct", product);

		whereListProduct(session);

		// when otherwise标签
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("price", 88.88);
		List<Product> products = session.selectList("chooseListProduct", map);
		for (Product product : products) {
			System.out.println(product);
		}

		// foreach标签
		List<Integer> integers = new ArrayList<Integer>();
		integers.add(1);
		integers.add(3);
		integers.add(5);

		List<Product> products = session.selectList("foreachListProduct", integers);
		for (Product product : products) {
			System.out.println(product);
		}

		// bind标签 Map<String, Object> map = new HashMap<String, Object>();
		map.put("name", "product");
		List<Product> products = session.selectList("bindListProductByName", map);
		for (Product product : products) {
			System.out.println(product);
		}

		session.commit();
		session.close();

		inputStream.close();
	}

// 多条件查询
	private static void whereListProduct(SqlSession session) {
		Map<String, Object> map = new HashMap<String, Object>();
		List<Product> products = session.selectList("whereListProduct", map);
		for (Product product : products) {
			System.out.println(product);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/the_programlife/article/details/80605659