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)


相关推荐

  • MyBatis返回复杂Map结果集「建议收藏」

    MyBatis返回复杂Map结果集「建议收藏」MyBatis返回复杂结果集key为指定属性,value为实体类结果集mybatis返回map,key为指定属性,value为实体类结果集

  • 10条PHP编程习惯助你找工作

    10条PHP编程习惯助你找工作

    2021年10月15日
  • MPEG学习

    MPEG学习Mpeg:movingpictureexpertsgroup移动图片专家组导入:Mpeg技术在我理解就是我们对音视频信息的一个输出标准。主要包括MPEG-1、MPEG-2、MPEG-4、MP

  • SQL分页查询方案的性能对比[通俗易懂]

    SQL分页查询方案的性能对比[通俗易懂]作者|中国农业银行吴海存责编|晋兆雨头图|CSDN下载自视觉中国导读本文主要介绍了基于ROWNUM、主键列/非空唯一性列、分析函数、OFFSET-FETCHNEXT机制的…

  • web图书销售管理系统_解读图书管理系统为书店带来的好处

    web图书销售管理系统_解读图书管理系统为书店带来的好处图书管理系统的出现,极大地推动了大中小型书店的发展,使书店管理工作更加高效成为书店管理的重要软件。其中图书管理系统给行业的好处更是大大方便了行业的运作。一、图书管理系统在书店中的应用,主要是为了进销存的目的,为了提高书店的效率加速发展,但没有选择合适的图书管理系统往往事与愿违。图书管理制度的选择是书店经营管理工作中的重要环节。图书管理系统,尤其是进销存功能,是书店在经营过程中对采购、销售、财务等进…

  • Linux基础_vim命令

     使用过LINUX操作系统的人应该都知道vim命令可以编写文本,对于没有接触过的同学通过以下介绍就可以轻松学会vim命令的使用方法。1.vim的工作模式 vim有三种工作模式,分别为命令模式,插入模式和退出模式。命令模式下不能编辑文本,通过i进入插入模式进行编辑,编辑完成后通过Esc键进入命令模式,在命令模式下输入:wq进行保存退出,其中w表示保存,q表示退出。2.vim常用工作参…

发表回复

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

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