04_MyBatis 单表 CRUD 和多表处理关联操作

04_MyBatis 单表 CRUD 和多表处理关联操作

MyBatis 单表 CRUD 操作

单标的CRUD操作,主要根据业务如何编写高质量的SQL语句.单标操作的时候如果表中的列和实体的属性不对应的时候,建议使用别名方式进行影射处理.

#{} / ${value}的区别

  • #{} 表示占位符
  • ${value}SQL字符串的拼接 里面必须写value。而#{} 可以任意写.如果参数类型是实体类,那么这里面写的是实体类中的属性名.

模糊查询SQL语句的写法


- SQL:select * from tb_user where username like '%username%'

- MyBatis:
	- select * from tb_user where username like concat('%',#{username},'%')
    
	- select * from tb_user where username like "%"#{username}""%";
	
	- select * from tb_user where username LIKE '%${value}%' ;
	    - ###如果传递是简单数据类型,使用${}里面必须写value

重构抽取重复的SQL

重构原则:写且一次,凡是不超过三次,如果超过三次,需要进行重构

在MyBatis中有一个SQL片段。把重复写的SQL进行抽取

<sql id="tbuser">
	username,
	password,
	email,
	phone
</sql>

使用<include refid="tbuser"/>
面向对象设计特性:封装、继承、多态.
重构原则:写且一次,凡是不超过三次,如果超过三次,需要进行重构

<?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="shop.tbzj.mapper.UserMapper">

    <sql id="tbUserInfo">
        a.id,
          a.username,
          a.password,
          a.phone,
          a.email,
          a.created,
          a.update
    </sql>

    <select id="selectAll" resultType="TbUser">
        SELECT
          <include refid="tbUserInfo"/>
        FROM
          tbuser AS a
    </select>

    <select id="selectByUsername" resultType="TbUser">
       SELECT

        <include refid="tbUserInfo"/>
  FROM
	tbuser AS a
  WHERE
	username

	LIKE CONCAT("%",#{username},"%");

    </select>
</mapper>

多表关联操作映射文件编写

单表或者一对一结果映射

- 单表操作如果实体属性和表列名称不一致,除了使用别名,
 还可以使用`resultMap`进行一对一的进行映射除了。
<?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="shop.tbzj.mapper.UserMapper">

    <sql id="tbUserInfo">
        a.id,
          a.username,
          a.password,
          a.phone,
          a.email,
          a.created,
          a.update
    </sql>

    <select id="selectAll" resultMap="tbUserMapping">
        SELECT
          <include refid="tbUserInfo"/>
        FROM
          tbuser AS a
    </select>

    <!-- resultMap最终还是要将结果映射到pojo上,type就是指定映射到哪一个pojo -->
    <resultMap id="tbUserMapping" type="TbUser">
        <!-- 定义主键 ,非常重要。如果是多个字段,则定义多个id -->
        <!-- property:主键在pojo中的属性名 -->
        <!-- column:主键在数据库中的列名 -->
       <!--定义主键 -->
        <id column="id" property="id"/>
        <!-- 定义普通属性 -->
        <result column="username" property="user_name"/>
        <result column="password" property="password"/>
        <result column="phone" property="phone"/>
        <result column="email" property="email"/>
        <result column="created" property="created"/>
        <result column="update" property="update"/>
    </resultMap>


<select id="selectByUsername" resultMap="tbUserMapping">
       SELECT
        <include refid="tbUserInfo"/>
        FROM
        	tbuser AS a
        WHERE
        	username
        LIKE CONCAT("%",#{username},"%");
</select>

实体类TbUser中的user_name和数据库tbuser表中的username 字段不一致,使用resultMap进行结果集映射处理

关联结果集映射

一对一

比如一个订单属于一个用户。

usernameuserName 可以对结果进行映射,但是user_nameusername 不能进行结果集映射。

比如用户表user 和订单表order的关系是一个用户对应多个订单。在查询的时候进行关联查询,查询的结果的映射有两种方式进行处理

  • 结果集映射使用resultType。
    专门使用一个pojo类包含订单信息和用户信息。
    比如:
    public class UserOrder extends Order{
    //-----下面的字段是用户信息的字段
    //通过继承方式把Order类的非私有字段继承过来.
        private Long id;
        private String user_name;
        private String password;
        private String phone;
        private String email;
        private Date created;
        private Date update;
        
    }
    
    在resultType中写"UserOrder“.
    
    
    <select id="queryOrderUser" resultType="orderUser">
	SELECT
    	o.id,
    	o.user_id
    	userId,
    	o.number,
    	o.createtime,
    	o.note,
    	u.username,
    	u.address
	FROM
	    `order` o
	LEFT JOIN 
	    `user` u ON o.user_id = u.id
</select>
    
有个缺点就是在java中的继承不能继承私有。如果子类访问父类的非私有属性和方法是通过关键字super()关键字进行访问.

被final修饰的类是不能被继承的。
  • 使用resultMap进行结果集映射
<resultMap type="order" id="orderUserResultMap">
	<id property="id" column="id" />
	<result property="userId" column="user_id" />
	<result property="number" column="number" />
	<result property="createtime" column="createtime" />
	<result property="note" column="note" />

	<!-- association :配置一对一属性 -->
	<!-- property:order里面的User属性名 -->
	<!-- javaType:属性类型 -->
	<association property="user" javaType="user">
		<!-- id:声明主键,表示user_id是关联查询对象的唯一标识-->
		<id property="id" column="user_id" />
		<result property="username" column="username" />
		<result property="address" column="address" />
	</association>
</resultMap>

<!-- 一对一关联,查询订单,订单内部包含用户属性 -->
<select id="queryOrderUserResultMap" resultMap="orderUserResultMap">
	SELECT
	o.id,
	o.user_id,
	o.number,
	o.createtime,
	o.note,
	u.username,
	u.address
	FROM
	`order` o
	LEFT JOIN `user` u ON o.user_id = u.id
</select>
一对多结果映射

比如:一个用户对一多个订单

public class User{
    private int id;
    private String username;
    private Date birthday;
    private String addres;
    //一个用户拥有多个订单使用List进程存储.
    private List<Order> orders;
}
UserMapper.xml的编写:

<resultMap type="user" id="userOrderResultMap">
	<id property="id" column="id" />
	<result property="username" column="username" />
	<result property="birthday" column="birthday" />
	<result property="sex" column="sex" />
	<result property="address" column="address" />

	<!-- 配置一对多的关系 -->
	<collection property="orders" javaType="list" ofType="order">
		<!-- 配置主键,是关联Order的唯一标识 -->
		<id property="id" column="oid" />
		<result property="number" column="number" />
		<result property="createtime" column="createtime" />
		<result property="note" column="note" />
	</collection>
</resultMap>

<!-- 一对多关联,查询订单同时查询该用户下的订单 -->
<select id="queryUserOrder" resultMap="userOrderResultMap">
	SELECT
	u.id,
	u.username,
	u.birthday,
	u.sex,
	u.address,
	o.id oid,
	o.number,
	o.createtime,
	o.note
	FROM
	`user` u
	LEFT JOIN `orders` o ON u.id = o.user_id
</select>
    

插入数据返回主键问题

  • MySQL中的表主键类型为自增类型
public class Order {
    private Long id;
    private String name;
    private Double price;
    }

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="shop.tbzj.mapper.OrderMapper">
    <insert id="insertOrder" useGeneratedKeys="true" keyProperty="id">
          insert into tb_order(name,price)values(#{name},#{price});
    </insert>
</mapper>

参考 中文官网MyBatis
useGeneratedKeys=“true” 开启获取主键
keyProperty=“id” 配置的是把获取的主键和实体类属性id进行对应映射

测试:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import shop.tbzj.entity.Order;
import shop.tbzj.mapper.OrderMapper;


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-context.xml")
public class TestOrder {

    @Autowired
    private OrderMapper orderMapper;

    @Test
    public void insertOrder() {
        Order order = new Order();
        order.setName("tom2");
        order.setPrice(22.3);

        orderMapper.insertOrder(order);
        //插入一条数据,吧主键id返回给实体类Order中的id
        System.out.println(order.toString());
    }

}

  • MySQL中的表主键类型为UUID类型
<!-- 保存订单 这里没有配置parameterType是因为在spring-contxt.xml中
    中的sqlSessionFactroy中进行配置了的
-->
<insert id="saveOrder">
	<!-- selectKey 标签实现主键返回 -->
	<!-- keyColumn:主键对应的表中的哪一列 -->
	<!-- keyProperty:主键对应的pojo中的哪一个属性 -->
	<!-- order:设置在执行insert语句前执行查询id的sql,还是在执行insert语句之后执行查询id的sql  uuid是BEFORE-->
	<!-- resultType:设置返回的id的类型 -->
	<selectKey keyColumn="id" keyProperty="id" order="BEFORE"
		resultType="string">
		SELECT LAST_INSERT_ID()
	</selectKey>
	insert into tb_order(id,name,price)values(#{id},#{name},#{price})
</insert>

select last_insert_id(); 查看最后插入的值是多少。

在分布式集群中如何解决主键ID冲突问题:
    这里讨论情况是id为自动增长的情况: 设置步长
        有个缺点,集群的数量如果有改动的话,需要重新设置步长。
        
    查询自增的步长
    SHOW VARIABLES LIKE 'auto_inc%'
    修改自增的步长
    SET @@auto_increment_increment=10;
    修改起始值
    SET @@auto_increment_offset=5;

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/100791.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • use mysql命令_mysql命令-use

    use mysql命令_mysql命令-useuse命令可以让我们来使用数据库。use命令格式:use;例如,如果xhkdb数据库存在,尝试存取它:mysql>usexhkdb;屏幕提示:Databasechanged1)use语句可以通告MySQL把db_name数据库作为默认(当前)数据库使用,用于后续语句。该数据库保持为默认数据库,直到语段的结尾,或者直到出现下一个不同的use语句:mysql>USEdb1…

  • 单片机流水灯程序[通俗易懂]

    单片机流水灯程序[通俗易懂]一、流水灯实验1、设计要求P1口接8个发光二极管,烧录程序后发光二极管依次点亮2、硬件要求利用proteusIsis仿真,选择器件,AT89C51、LED-BLUE、RES3、软件设计源程序:/*********************必要变量定义******************/#include&lt;reg51.h&gt;#include&lt;intrns.h&gt;…

  • VS2017 注册

    VS2017 注册VisualStudio2017序列号Key激活码VS2017注册码VisualStudio2017(VS2017)企业版 Enterprise注册码 序列

  • 手机NFC模拟M1门禁卡、写CUID白卡的一些研究记录

    手机NFC模拟M1门禁卡、写CUID白卡的一些研究记录一、需求场景近来小区安装了智能门禁,但只配发了一张门禁卡,不方便使用,于是产生了用手机模拟门禁卡,或者复制一张门禁卡的想法。本文使用的软件:(CSDN无法修改下载积分了。。。)包括手机NFC读写卡神器MifareClassicTool(MCT)2.2.5最新版、手机读卡工具NFCTagInfo、NFC卡模拟软件Cardemulator、RE管理器,以及一款NFC模拟…

  • python3.7官网下载步骤_python下载(python官网下载步骤)「建议收藏」

    python3.7官网下载步骤_python下载(python官网下载步骤)「建议收藏」1.打开官方网站,光标移到Downloads,选择windows2.2018年2月28日,python发布了3.7版本。根据不同的操作系统,选择不同版本的安装包。每一个版本提供了三个下载链接,依次是基于网页的安装程序、可执行的安装程序、程序的压缩文件。通常选择下载可执行的安装程序。32位的操作系统请选择windowsx86,64位操作系统请选择windowsx86-64。3.双击打开下载好的安装包…

  • Linux 系列:awk 数组的用法

    Linux 系列:awk 数组的用法demo

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号