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进行结果集映射处理
关联结果集映射
一对一
比如一个订单属于一个用户。
username
和userName
可以对结果进行映射,但是user_name
和username
不能进行结果集映射。
比如用户表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账号...