<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ORM &#8211; chang的个人博客</title>
	<atom:link href="https://www.qiqin-chang.cn/category/back/orm/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.qiqin-chang.cn</link>
	<description></description>
	<lastBuildDate>Sun, 28 Dec 2025 19:37:42 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://www.qiqin-chang.cn/wp-content/uploads/2025/04/cropped-无背景-圆形-32x32.png</url>
	<title>ORM &#8211; chang的个人博客</title>
	<link>https://www.qiqin-chang.cn</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>MyBatis-持久层框架</title>
		<link>https://www.qiqin-chang.cn/mybatis-%e6%8c%81%e4%b9%85%e5%b1%82%e6%a1%86%e6%9e%b6%ef%bc%9a/</link>
					<comments>https://www.qiqin-chang.cn/mybatis-%e6%8c%81%e4%b9%85%e5%b1%82%e6%a1%86%e6%9e%b6%ef%bc%9a/#respond</comments>
		
		<dc:creator><![CDATA[乐章]]></dc:creator>
		<pubDate>Tue, 02 Sep 2025 13:47:51 +0000</pubDate>
				<category><![CDATA[ORM]]></category>
		<category><![CDATA[后端]]></category>
		<guid isPermaLink="false">http://www.qiqin-chang.cn/?p=559</guid>

					<description><![CDATA[官方网站：https://mybatis.org/mybatis-3/zh_CN/index.html 依赖： [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">官方网站：<a href="https://mybatis.org/mybatis-3/zh_CN/index.html">https://mybatis.org/mybatis-3/zh_CN/index.html</a></h2>



<h2 class="wp-block-heading">依赖：</h2>



<pre class="wp-block-code"><code>&lt;!-- MyBatis 持久层框架 --&gt;<br>&lt;dependency&gt;<br> &nbsp; &nbsp;&lt;groupId&gt;org.mybatis.spring.boot&lt;/groupId&gt;<br> &nbsp; &nbsp;&lt;artifactId&gt;mybatis-spring-boot-starter&lt;/artifactId&gt;<br> &nbsp; &nbsp;&lt;version&gt;3.0.5&lt;/version&gt;<br>&lt;/dependency&gt;</code></pre>



<h2 class="wp-block-heading">配置：</h2>



<pre class="wp-block-code"><code>## MyBatis配置与xml映射<br>mybatis:<br> &nbsp;## 映射xml<br>  mapper-locations: classpath:mapper/*.xml <br>  configuration:<br> &nbsp; &nbsp;## 日志配置<br> &nbsp;  log-impl: org.apache.ibatis.logging.stdout.StdOutImpl<br> &nbsp; &nbsp;## 映射格式转换<br> &nbsp;  map-underscore-to-camel-case: true</code></pre>



<h2 class="wp-block-heading">自动映射：</h2>



<p>Java：驼峰命名：departmentId</p>



<p>数据库：下划线：department_id</p>



<h2 class="wp-block-heading">mapper包扫描：</h2>



<p>启动类注解：</p>



<pre class="wp-block-code"><code>@MapperScan("com.chang.mapper")</code></pre>



<h2 class="wp-block-heading">XML基础模版：</h2>



<pre class="wp-block-code"><code>&lt;?xml version="1.0" encoding="UTF-8" ?&gt;<br>&lt;!DOCTYPE mapper<br> &nbsp; &nbsp; &nbsp; &nbsp;PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"<br> &nbsp; &nbsp; &nbsp; &nbsp;"https://mybatis.org/dtd/mybatis-3-mapper.dtd"&gt;<br>&lt;mapper namespace="对应mapper接口引用"&gt;<br> &nbsp; &nbsp;<br>&lt;/mapper&gt;</code></pre>



<h3 class="wp-block-heading">XML格式：</h3>



<pre class="wp-block-code"><code>&lt;select id="selectAll" resultType="com.chang.entity.Employee"&gt; &lt;!--id对应方法名 resultType：结果类型 对应实体类引用--&gt;<br> &nbsp;  select * from employee<br> &nbsp; &nbsp;&lt;where&gt;<br> &nbsp; &nbsp; &nbsp; &nbsp;&lt;if test="name!=null"&gt;name like concat('%',#{name},'%')&lt;/if&gt;<br> &nbsp; &nbsp;&lt;/where&gt;<br>&lt;/select&gt;<br>​<br>&lt;insert id="insert" parameterType="com.chang.entity.Employee"&gt; &lt;!--parameterType：参数类型--&gt;<br> &nbsp;  insert into `employee` (name,sex,no,age,description,department_id) &lt;!--下划线命名法--&gt;<br> &nbsp;  values (#{name},#{sex},#{no},#{age},#{description},#{departmentId}) &lt;!--驼峰命名--&gt;<br>&lt;/insert&gt;</code></pre>



<h3 class="wp-block-heading">注解查询：</h3>



<pre class="wp-block-code"><code>@Select("select * from employee where id = #{id}")<br>Employee selectById(Integer id);</code></pre>



<h2 class="wp-block-heading">代码模版：</h2>



<h3 class="wp-block-heading">Mapper:</h3>



<pre class="wp-block-code"><code>package com.chang.mapper;<br>​<br>public interface EmployeeMapper {<br>}</code></pre>



<h3 class="wp-block-heading">Service:</h3>



<pre class="wp-block-code"><code>package com.chang.service;<br>​<br>import org.springframework.stereotype.Service;<br>​<br>@Service<br>public class EmployeeService {<br>}</code></pre>



<h2 class="wp-block-heading">分页插件-分页查询：</h2>



<h3 class="wp-block-heading">依赖：</h3>



<pre class="wp-block-code"><code>&lt;!--PageHelper 分页插件--&gt;<br>&lt;dependency&gt;<br> &nbsp; &nbsp;&lt;groupId&gt;com.github.pagehelper&lt;/groupId&gt;<br> &nbsp; &nbsp;&lt;artifactId&gt;pagehelper-spring-boot-starter&lt;/artifactId&gt;<br> &nbsp; &nbsp;&lt;version&gt;1.4.6&lt;/version&gt;<br> &nbsp; &nbsp;&lt;exclusions&gt;<br> &nbsp; &nbsp; &nbsp; &lt;exclusion&gt;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;groupId&gt;org.mybatis&lt;/groupId&gt;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;artifactId&gt;mybatis&lt;/artifactId&gt;<br> &nbsp; &nbsp; &nbsp; &lt;/exclusion&gt;<br> &nbsp; &nbsp;&lt;/exclusions&gt;<br>&lt;/dependency&gt;</code></pre>



<h3 class="wp-block-heading">代码：</h3>



<h4 class="wp-block-heading">controller：</h4>



<pre class="wp-block-code"><code>/**<br> * 分页查询数据<br> * pageNum: 当前页码<br> * pageSize: 每页的个数<br> */<br>@GetMapping("/selectPage")<br>public Result selectPage(@RequestParam(defaultValue = "1") Integer pageNum,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @RequestParam(defaultValue = "10") Integer pageSize){<br> &nbsp; &nbsp;PageInfo&lt;Employee&gt; pageInfo = employeeService.selectPage(pageNum, pageSize);<br> &nbsp; &nbsp;return Result.success(pageInfo);<br>}</code></pre>



<h4 class="wp-block-heading">service：</h4>



<pre class="wp-block-code"><code>@Override<br>public PageInfo&lt;Employee&gt; selectPage(Integer pageNum, Integer pageSize) {<br> &nbsp; &nbsp;PageHelper.startPage(pageNum, pageSize);<br> &nbsp; &nbsp;List&lt;Employee&gt; list = employeeMapper.selectAll();<br> &nbsp; &nbsp;return PageInfo.of(list) ;<br>}</code></pre>



<h2 class="wp-block-heading">CRUD：</h2>



<h3 class="wp-block-heading">Controller层：</h3>



<pre class="wp-block-code"><code>package com.chang.controller;<br>​<br>import com.chang.common.Result;<br>import com.chang.entity.Employee;<br>import com.chang.service.EmployeeService;<br>import com.github.pagehelper.PageInfo;<br>import org.springframework.beans.factory.annotation.Autowired;<br>import org.springframework.web.bind.annotation.*;<br>​<br>import java.util.List;<br>​<br>@RestController<br>@RequestMapping("/employee")<br>public class EmployeeController {<br>​<br> &nbsp; &nbsp;@Autowired<br> &nbsp; &nbsp;private EmployeeService employeeService;<br>​<br> &nbsp; &nbsp;/**<br> &nbsp; &nbsp; * 查询单个数据<br> &nbsp; &nbsp; */<br> &nbsp; &nbsp;@GetMapping("/selectById/{id}")<br> &nbsp; &nbsp;public Result selectById(@PathVariable Integer id){<br> &nbsp; &nbsp; &nbsp; &nbsp;Employee employee = employeeService.selectById(id);<br> &nbsp; &nbsp; &nbsp; &nbsp;return Result.success(employee);<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;/**<br> &nbsp; &nbsp; * 查询所有的数据<br> &nbsp; &nbsp; */<br> &nbsp; &nbsp;@GetMapping("/selectAll")<br> &nbsp; &nbsp;public Result selectAll(){<br> &nbsp; &nbsp; &nbsp; &nbsp;List&lt;Employee&gt; list = employeeService.selectAll();<br> &nbsp; &nbsp; &nbsp; &nbsp;return Result.success(list);<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;/**<br> &nbsp; &nbsp; * 分页查询数据<br> &nbsp; &nbsp; * pageNum: 当前页码<br> &nbsp; &nbsp; * pageSize: 每页的个数<br> &nbsp; &nbsp; */<br> &nbsp; &nbsp;@GetMapping("/selectPage")<br> &nbsp; &nbsp;public Result selectPage(@RequestParam(defaultValue = "1") Integer pageNum,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @RequestParam(defaultValue = "10") Integer pageSize){<br> &nbsp; &nbsp; &nbsp; &nbsp;PageInfo&lt;Employee&gt; pageInfo = employeeService.selectPage(pageNum, pageSize);<br> &nbsp; &nbsp; &nbsp; &nbsp;return Result.success(pageInfo);<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;/**<br> &nbsp; &nbsp; * 新增数据<br> &nbsp; &nbsp; */<br> &nbsp; &nbsp;@PostMapping("/add")<br> &nbsp; &nbsp;public Result add(@RequestBody Employee employee){<br> &nbsp; &nbsp; &nbsp; &nbsp;employeeService.add(employee);<br> &nbsp; &nbsp; &nbsp; &nbsp;return Result.success();<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;/**<br> &nbsp; &nbsp; * 跟新数据<br> &nbsp; &nbsp; */<br> &nbsp; &nbsp;@PutMapping("/update")<br> &nbsp; &nbsp;public Result update(@RequestBody Employee employee){<br> &nbsp; &nbsp; &nbsp; &nbsp;employeeService.update(employee);<br> &nbsp; &nbsp; &nbsp; &nbsp;return Result.success();<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;/**<br> &nbsp; &nbsp; * 删除单个数据<br> &nbsp; &nbsp; */<br> &nbsp; &nbsp;@DeleteMapping("/deleteById/{id}")<br> &nbsp; &nbsp;public Result update(@PathVariable Integer id){<br> &nbsp; &nbsp; &nbsp; &nbsp;employeeService.deleteById(id);<br> &nbsp; &nbsp; &nbsp; &nbsp;return Result.success();<br> &nbsp;  }<br>}</code></pre>



<h3 class="wp-block-heading">ServiceImpl接口：</h3>



<pre class="wp-block-code"><code>package com.chang.service.impl;<br>​<br>import com.chang.entity.Employee;<br>import com.github.pagehelper.PageInfo;<br>​<br>import java.util.List;<br>​<br>public interface EmployeeServiceImpl {<br>​<br> &nbsp; &nbsp;Employee selectById(Integer id);<br>​<br> &nbsp; &nbsp;List&lt;Employee&gt; selectAll();<br>​<br> &nbsp; &nbsp;PageInfo&lt;Employee&gt; selectPage(Integer pageNum, Integer pageSize);<br>​<br> &nbsp; &nbsp;void add(Employee employee);<br>​<br> &nbsp; &nbsp;void update(Employee employee);<br>​<br> &nbsp; &nbsp;void deleteById(Integer id);<br>}</code></pre>



<h3 class="wp-block-heading">Service层：</h3>



<pre class="wp-block-code"><code>package com.chang.service;<br>​<br>import com.chang.entity.Employee;<br>import com.chang.mapper.EmployeeMapper;<br>import com.chang.service.impl.EmployeeServiceImpl;<br>import com.github.pagehelper.PageHelper;<br>import com.github.pagehelper.PageInfo;<br>import org.springframework.beans.factory.annotation.Autowired;<br>import org.springframework.stereotype.Service;<br>​<br>import java.util.List;<br>​<br>@Service<br>public class EmployeeService implements EmployeeServiceImpl {<br>​<br> &nbsp; &nbsp;@Autowired<br> &nbsp; &nbsp;private EmployeeMapper employeeMapper;<br>​<br> &nbsp; &nbsp;@Override<br> &nbsp; &nbsp;public Employee selectById(Integer id) {<br> &nbsp; &nbsp; &nbsp; &nbsp;return employeeMapper.selectById(id);<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;@Override<br> &nbsp; &nbsp;public List&lt;Employee&gt; selectAll() {<br> &nbsp; &nbsp; &nbsp; &nbsp;//额外业务操作<br> &nbsp; &nbsp; &nbsp; &nbsp;return employeeMapper.selectAll();<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;@Override<br> &nbsp; &nbsp;public PageInfo&lt;Employee&gt; selectPage(Integer pageNum, Integer pageSize) {<br> &nbsp; &nbsp; &nbsp; &nbsp;PageHelper.startPage(pageNum, pageSize);<br> &nbsp; &nbsp; &nbsp; &nbsp;List&lt;Employee&gt; list = employeeMapper.selectAll();<br> &nbsp; &nbsp; &nbsp; &nbsp;return PageInfo.of(list) ;<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;@Override<br> &nbsp; &nbsp;public void add(Employee employee) {<br> &nbsp; &nbsp; &nbsp; &nbsp;employeeMapper.insert(employee);<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;@Override<br> &nbsp; &nbsp;public void update(Employee employee) {<br> &nbsp; &nbsp; &nbsp; &nbsp;employeeMapper.updateById(employee);<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;@Override<br> &nbsp; &nbsp;public void deleteById(Integer id) {<br> &nbsp; &nbsp; &nbsp; &nbsp;employeeMapper.deleteById(id);<br> &nbsp;  }<br>​<br>}</code></pre>



<h3 class="wp-block-heading">Mapper层：</h3>



<pre class="wp-block-code"><code>package com.chang.mapper;<br>​<br>import com.chang.entity.Employee;<br>import org.apache.ibatis.annotations.Delete;<br>import org.apache.ibatis.annotations.Select;<br>​<br>import java.util.List;<br>​<br>public interface EmployeeMapper {<br>​<br> &nbsp; &nbsp;List&lt;Employee&gt; selectAll();<br>​<br> &nbsp; &nbsp;@Select("select * from `employee` where id = #{id}")<br> &nbsp; &nbsp;Employee selectById(Integer id);<br>​<br> &nbsp; &nbsp;void insert(Employee employee);<br>​<br> &nbsp; &nbsp;void updateById(Employee employee);<br>​<br> &nbsp; &nbsp;@Delete("delete from `employee` where id = #{id}")<br> &nbsp; &nbsp;void deleteById(Integer id);<br>}</code></pre>



<h3 class="wp-block-heading">XML文件：</h3>



<pre class="wp-block-code"><code>&lt;?xml version="1.0" encoding="UTF-8" ?&gt;<br>&lt;!DOCTYPE mapper<br> &nbsp; &nbsp; &nbsp; &nbsp;PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"<br> &nbsp; &nbsp; &nbsp; &nbsp;"https://mybatis.org/dtd/mybatis-3-mapper.dtd"&gt;<br>&lt;mapper namespace="com.chang.mapper.EmployeeMapper"&gt;<br>​<br> &nbsp; &nbsp;&lt;select id="selectAll" resultType="com.chang.entity.Employee"&gt;<br> &nbsp; &nbsp; &nbsp;  select * from employee<br> &nbsp; &nbsp;&lt;/select&gt;<br>​<br> &nbsp; &nbsp;&lt;insert id="insert" parameterType="com.chang.entity.Employee"&gt;<br> &nbsp; &nbsp; &nbsp;  insert into `employee` (name,sex,no,age,description,department_id)<br> &nbsp; &nbsp; &nbsp;  values (#{name},#{sex},#{no},#{age},#{description},#{departmentId})<br> &nbsp; &nbsp;&lt;/insert&gt;<br>​<br> &nbsp; &nbsp;&lt;update id="updateById" parameterType="com.chang.entity.Employee"&gt;<br> &nbsp; &nbsp; &nbsp;  update `employee` set name = #{name},sex = #{sex},no=#{no},age=#{age},<br> &nbsp; &nbsp; &nbsp;  description=#{description},department_id=#{departmentId}<br> &nbsp; &nbsp; &nbsp;  where id=#{id}<br> &nbsp; &nbsp;&lt;/update&gt;<br>​<br>&lt;/mapper&gt;</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://www.qiqin-chang.cn/mybatis-%e6%8c%81%e4%b9%85%e5%b1%82%e6%a1%86%e6%9e%b6%ef%bc%9a/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>MybatisPlus-持久层框架</title>
		<link>https://www.qiqin-chang.cn/mybatisplus-%e6%8c%81%e4%b9%85%e5%b1%82%e6%a1%86%e6%9e%b6/</link>
					<comments>https://www.qiqin-chang.cn/mybatisplus-%e6%8c%81%e4%b9%85%e5%b1%82%e6%a1%86%e6%9e%b6/#respond</comments>
		
		<dc:creator><![CDATA[乐章]]></dc:creator>
		<pubDate>Wed, 09 Apr 2025 12:19:23 +0000</pubDate>
				<category><![CDATA[ORM]]></category>
		<category><![CDATA[后端]]></category>
		<guid isPermaLink="false">http://8.153.197.211/?p=52</guid>

					<description><![CDATA[基础信息： 官方地址：https://www.baomidou.com/ 依赖： SpringBoot2： &#038; [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading">基础信息：</h1>



<h2 class="wp-block-heading">官方地址：<a href="https://www.baomidou.com/">https://www.baomidou.com/</a></h2>



<h2 class="wp-block-heading">依赖：</h2>



<p>SpringBoot2：</p>



<pre class="wp-block-preformatted">&lt;dependency&gt;<br> &nbsp; &nbsp;&lt;groupId&gt;com.baomidou&lt;/groupId&gt;<br> &nbsp; &nbsp;&lt;artifactId&gt;mybatis-plus-boot-starter&lt;/artifactId&gt;<br> &nbsp; &nbsp;&lt;version&gt;3.5.10.1&lt;/version&gt;<br>&lt;/dependency&gt;</pre>



<p>SpringBoot3：</p>



<pre class="wp-block-preformatted">&lt;dependency&gt;<br> &nbsp; &nbsp;&lt;groupId&gt;com.baomidou&lt;/groupId&gt;<br> &nbsp; &nbsp;&lt;artifactId&gt;mybatis-plus-spring-boot3-starter&lt;/artifactId&gt;<br> &nbsp; &nbsp;&lt;version&gt;3.5.10.1&lt;/version&gt;<br>&lt;/dependency&gt;</pre>



<p>测试依赖：</p>



<pre class="wp-block-preformatted">&lt;dependency&gt;<br> &nbsp; &nbsp;&lt;groupId&gt;com.baomidou&lt;/groupId&gt;<br> &nbsp; &nbsp;&lt;artifactId&gt;mybatis-plus-boot-starter-test&lt;/artifactId&gt;<br> &nbsp; &nbsp;&lt;version&gt;3.5.10.1&lt;/version&gt;<br>&lt;/dependency&gt;</pre>



<h1 class="wp-block-heading">配置：</h1>



<h2 class="wp-block-heading">常见配置：</h2>



<p>说明：可不配</p>



<pre class="wp-block-preformatted">mybatis-plus:<br>  type-aliases-package: com.chang.*.*.pojo #实体类位置(改成自己的实体类位置)<br>  mapper-locations: "classpath*:/mapper/**/*.xml" # Mapper.xml文件的存放地址（当前这个是默认值）。<br> &nbsp;<br>  global-config:<br> &nbsp;  db-config:<br> &nbsp; &nbsp;  id-type: auto # 全局id类型为自增长 &nbsp; </pre>



<h2 class="wp-block-heading">XML文件模版：</h2>



<pre class="wp-block-preformatted">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;<br>&lt;!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"<br> &nbsp; &nbsp; &nbsp; &nbsp;"http://mybatis.org/dtd/mybatis-3-mapper.dtd" &gt;<br>&lt;mapper namespace="com.chang.mapper.UserMapper"&gt;<br>    &lt;!--内容--&gt;<br>&lt;/mapper&gt;</pre>



<h2 class="wp-block-heading">动态XML：</h2>



<pre class="wp-block-preformatted">    &lt;foreach collection="ids" separator="," item="id" open="IN (" close=")"&gt;<br>        #{id}<br>    &lt;/foreach&gt;</pre>



<pre class="wp-block-preformatted">    &lt;if test="status != null"&gt;<br> &nbsp; &nbsp; &nbsp;  status = #{status}<br>    &lt;/if&gt;</pre>



<h1 class="wp-block-heading">定义Mapper</h1>



<h2 class="wp-block-heading">继承BaseMapper</h2>



<p>实现单表CRUD</p>



<pre class="wp-block-preformatted">public interface UserMapper extends BaseMapper&lt;User&gt; {<br>}</pre>



<h2 class="wp-block-heading">单元测试:</h2>



<p>说明：单表增删改查</p>



<pre class="wp-block-preformatted">@SpringBootTest<br>class UserMapperTest {<br>​<br> &nbsp; &nbsp;@Autowired<br> &nbsp; &nbsp;private UserMapper userMapper;<br>​<br> &nbsp; &nbsp;@Test<br> &nbsp; &nbsp;void testInsert() {<br> &nbsp; &nbsp; &nbsp; &nbsp;User user = new User();<br> &nbsp; &nbsp; &nbsp; &nbsp;user.setId(5L);<br> &nbsp; &nbsp; &nbsp; &nbsp;user.setUsername("Lucy");<br> &nbsp; &nbsp; &nbsp; &nbsp;user.setPassword("123");<br> &nbsp; &nbsp; &nbsp; &nbsp;user.setPhone("18688990011");<br> &nbsp; &nbsp; &nbsp; &nbsp;user.setBalance(200);<br> &nbsp; &nbsp; &nbsp; &nbsp;user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");<br> &nbsp; &nbsp; &nbsp; &nbsp;user.setCreateTime(LocalDateTime.now());<br> &nbsp; &nbsp; &nbsp; &nbsp;user.setUpdateTime(LocalDateTime.now());<br> &nbsp; &nbsp; &nbsp; &nbsp;userMapper.insert(user);<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;@Test<br> &nbsp; &nbsp;void testSelectById() {<br> &nbsp; &nbsp; &nbsp; &nbsp;User user = userMapper.selectById(5L);<br> &nbsp; &nbsp; &nbsp; &nbsp;System.out.println("user = " + user);<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;@Test<br> &nbsp; &nbsp;void testSelectByIds() {<br> &nbsp; &nbsp; &nbsp; &nbsp;List&lt;User&gt; users = userMapper.selectBatchIds(List.of(1L, 2L, 3L, 4L, 5L));<br> &nbsp; &nbsp; &nbsp; &nbsp;users.forEach(System.out::println);<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;@Test<br> &nbsp; &nbsp;void testUpdateById() {<br> &nbsp; &nbsp; &nbsp; &nbsp;User user = new User();<br> &nbsp; &nbsp; &nbsp; &nbsp;user.setId(5L);<br> &nbsp; &nbsp; &nbsp; &nbsp;user.setBalance(20000);<br> &nbsp; &nbsp; &nbsp; &nbsp;userMapper.updateById(user);<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;@Test<br> &nbsp; &nbsp;void testDelete() {<br> &nbsp; &nbsp; &nbsp; &nbsp;userMapper.deleteById(5L);<br> &nbsp;  }<br>}</pre>



<h1 class="wp-block-heading">实体注解：</h1>



<h2 class="wp-block-heading">@TableName</h2>



<p>说明：</p>



<ul class="wp-block-list">
<li>描述：表名注解，标识实体类对应的表</li>



<li>使用位置：实体类</li>
</ul>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th><strong>属性</strong></th><th><strong>类型</strong></th><th><strong>必须指定</strong></th><th><strong>默认值</strong></th><th><strong>描述</strong></th></tr></thead><tbody><tr><td>value</td><td>String</td><td>否</td><td>&#8220;&#8221;</td><td>表名</td></tr><tr><td>schema</td><td>String</td><td>否</td><td>&#8220;&#8221;</td><td>schema</td></tr><tr><td>keepGlobalPrefix</td><td>boolean</td><td>否</td><td>false</td><td>是否保持使用全局的 tablePrefix 的值（当全局 tablePrefix 生效时）</td></tr><tr><td>resultMap</td><td>String</td><td>否</td><td>&#8220;&#8221;</td><td>xml 中 resultMap 的 id（用于满足特定类型的实体类对象绑定）</td></tr><tr><td>autoResultMap</td><td>boolean</td><td>否</td><td>false</td><td>是否自动构建 resultMap 并使用（如果设置 resultMap 则不会进行 resultMap 的自动构建与注入）</td></tr><tr><td>excludeProperty</td><td>String[]</td><td>否</td><td>{}</td><td>需要排除的属性名 @since 3.3.1</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">@TableId</h2>



<p>说明：</p>



<ul class="wp-block-list">
<li>描述：主键注解，标识实体类中的主键字段</li>



<li>使用位置：实体类的主键字段</li>
</ul>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th><strong>属性</strong></th><th><strong>类型</strong></th><th><strong>必须指定</strong></th><th><strong>默认值</strong></th><th><strong>描述</strong></th></tr></thead><tbody><tr><td>value</td><td>String</td><td>否</td><td>&#8220;&#8221;</td><td>表名</td></tr><tr><td>type</td><td>Enum</td><td>否</td><td>IdType.NONE</td><td>指定主键类型</td></tr></tbody></table></figure>



<p>IdType类型有：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th><strong>值</strong></th><th><strong>描述</strong></th></tr></thead><tbody><tr><td>AUTO</td><td>数据库 ID 自增</td></tr><tr><td>NONE</td><td>无状态，该类型为未设置主键类型（注解里等于跟随全局，全局里约等于 INPUT）</td></tr><tr><td>INPUT</td><td>insert 前手动生成主键值</td></tr><tr><td>ASSIGN_ID</td><td>分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)</td></tr><tr><td>ASSIGN_UUID</td><td>分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认 default 方法)</td></tr></tbody></table></figure>



<h2 class="wp-block-heading"><strong>@TableField</strong></h2>



<p>说明：</p>



<ul class="wp-block-list">
<li>成员变量名与数据库字段名不一致</li>



<li>成员变量是以<code>isXXX</code>命名，按照<code>JavaBean</code>的规范，<code>MybatisPlus</code>识别字段时会把<code>is</code>去除，这就导致与数据库不符。</li>



<li>成员变量名与数据库一致，但是与数据库的关键字冲突。使用<code>@TableField</code>注解给字段名添加转义字符：&#8220;&#8220;</li>
</ul>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th><strong>属性</strong></th><th><strong>类型</strong></th><th><strong>必填</strong></th><th><strong>默认值</strong></th><th><strong>描述</strong></th></tr></thead><tbody><tr><td>value</td><td>String</td><td>否</td><td>&#8220;&#8221;</td><td>数据库字段名</td></tr><tr><td>exist</td><td>boolean</td><td>否</td><td>true</td><td>是否为数据库表字段</td></tr><tr><td>condition</td><td>String</td><td>否</td><td>&#8220;&#8221;</td><td>字段 where 实体查询比较条件，有值设置则按设置的值为准，没有则为默认全局的 %s=#{%s}，<a href="https://github.com/baomidou/mybatis-plus/blob/3.0/mybatis-plus-annotation/src/main/java/com/baomidou/mybatisplus/annotation/SqlCondition.java">参考(opens new window)</a></td></tr><tr><td>update</td><td>String</td><td>否</td><td>&#8220;&#8221;</td><td>字段 update set 部分注入，例如：当在version字段上注解update=&#8221;%s+1&#8243; 表示更新时会 set version=version+1 （该属性优先级高于 el 属性）</td></tr><tr><td>insertStrategy</td><td>Enum</td><td>否</td><td>FieldStrategy.DEFAULT</td><td>举例：NOT_NULL insert into table_a(&lt;if test=&#8221;columnProperty != null&#8221;&gt;column&lt;/if&gt;) values (&lt;if test=&#8221;columnProperty != null&#8221;&gt;#{columnProperty}&lt;/if&gt;)</td></tr><tr><td>updateStrategy</td><td>Enum</td><td>否</td><td>FieldStrategy.DEFAULT</td><td>举例：IGNORED update table_a set column=#{columnProperty}</td></tr><tr><td>whereStrategy</td><td>Enum</td><td>否</td><td>FieldStrategy.DEFAULT</td><td>举例：NOT_EMPTY where &lt;if test=&#8221;columnProperty != null and columnProperty!=&#8221;&#8221;&gt;column=#{columnProperty}&lt;/if&gt;</td></tr><tr><td>fill</td><td>Enum</td><td>否</td><td>FieldFill.DEFAULT</td><td>字段自动填充策略</td></tr><tr><td>select</td><td>boolean</td><td>否</td><td>true</td><td>是否进行 select 查询</td></tr><tr><td>keepGlobalFormat</td><td>boolean</td><td>否</td><td>false</td><td>是否保持使用全局的 format 进行处理</td></tr><tr><td>jdbcType</td><td>JdbcType</td><td>否</td><td>JdbcType.UNDEFINED</td><td>JDBC 类型 (该默认值不代表会按照该值生效)</td></tr><tr><td>typeHandler</td><td>TypeHander</td><td>否</td><td></td><td>类型处理器 (该默认值不代表会按照该值生效)</td></tr><tr><td>numericScale</td><td>String</td><td>否</td><td>&#8220;&#8221;</td><td>指定小数点后保留的位数</td></tr></tbody></table></figure>



<h1 class="wp-block-heading">核心功能：</h1>



<h2 class="wp-block-heading">条件构造器：</h2>



<p>构筑复杂的where条件。</p>





<p>参数Wrapper是条件构造的抽象类，继承关系如图：</p>





<p>Wrapper的子类AbstractWrapper提供了where中包含的所有条件构造方法：</p>





<p>而QueryWrapper在AbstractWrapper的基础上拓展了一个select方法，允许指定查询字段：</p>





<p>而UpdateWrapper在AbstractWrapper的基础上拓展了一个set方法，允许指定SQL中的SET部分：</p>





<h3 class="wp-block-heading">QueryWrapper</h3>



<p>构建查询条件：</p>



<p><strong>查询</strong>：查询出名字中带<code>o</code>的，存款大于等于1000元的人。代码如下：</p>



<pre class="wp-block-preformatted">@Test<br>void testQueryWrapper() {<br> &nbsp; &nbsp;// 1.构建查询条件 where name like "%o%" AND balance &gt;= 1000<br> &nbsp; &nbsp;QueryWrapper&lt;User&gt; wrapper = new QueryWrapper&lt;User&gt;()<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .select("id", "username", "info", "balance")<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .like("username", "o")<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .ge("balance", 1000);<br> &nbsp; &nbsp;// 2.查询数据<br> &nbsp; &nbsp;List&lt;User&gt; users = userMapper.selectList(wrapper);<br> &nbsp; &nbsp;users.forEach(System.out::println);<br>}</pre>



<p><strong>更新</strong>：更新用户名为jack的用户的余额为2000，代码如下：</p>



<pre class="wp-block-preformatted">@Test<br>void testUpdateByQueryWrapper() {<br> &nbsp; &nbsp;// 1.构建查询条件 where name = "Jack"<br> &nbsp; &nbsp;QueryWrapper&lt;User&gt; wrapper = new QueryWrapper&lt;User&gt;().eq("username", "Jack");<br> &nbsp; &nbsp;// 2.更新数据，user中非null字段都会作为set语句<br> &nbsp; &nbsp;User user = new User();<br> &nbsp; &nbsp;user.setBalance(2000);<br> &nbsp; &nbsp;userMapper.update(user, wrapper);<br>}</pre>



<h3 class="wp-block-heading">UpdateWrapper：</h3>



<p>构建更新语句：基于BaseMapper中的update方法更新时只能直接赋值，对于一些复杂的需求就难以实现。</p>



<p>更新：id为<code>1,2,4</code>的用户的余额，扣200</p>



<pre class="wp-block-preformatted">@Test<br>void testUpdateWrapper() {<br> &nbsp; &nbsp;List&lt;Long&gt; ids = List.of(1L, 2L, 4L);<br> &nbsp; &nbsp;// 1.生成SQL<br> &nbsp; &nbsp;UpdateWrapper&lt;User&gt; wrapper = new UpdateWrapper&lt;User&gt;()<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .setSql("balance = balance - 200") // SET balance = balance - 200<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .in("id", ids); // WHERE id in (1, 2, 4)<br> &nbsp; &nbsp; &nbsp; &nbsp;// 2.更新，注意第一个参数可以给null，也就是不填更新字段和数据，<br> &nbsp; &nbsp;// 而是基于UpdateWrapper中的setSQL来更新<br> &nbsp; &nbsp;userMapper.update(null, wrapper);<br>}</pre>



<h3 class="wp-block-heading">LambdaQueryWrapper：</h3>



<p>基于变量的<code>gettter</code>方法结合反射技术。我们只要将条件对应的字段的<code>getter</code>方法传递给MybatisPlus，它就能计算出对应的变量名了。而传递方法可以使用JDK8中的方法引用和Lambda表达式。 因此MybatisPlus又提供了一套基于Lambda的Wrapper，包含两个：</p>



<ul class="wp-block-list">
<li>LambdaQueryWrapper</li>



<li>LambdaUpdateWrapper</li>
</ul>



<p>分别对应QueryWrapper和UpdateWrapper</p>



<p>其使用方式如下：</p>



<pre class="wp-block-preformatted">@Test<br>void testLambdaQueryWrapper() {<br> &nbsp; &nbsp;// 1.构建条件 WHERE username LIKE "%o%" AND balance &gt;= 1000<br> &nbsp; &nbsp;QueryWrapper&lt;User&gt; wrapper = new QueryWrapper&lt;&gt;();<br> &nbsp; &nbsp;wrapper.lambda()<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .select(User::getId, User::getUsername, User::getInfo, User::getBalance)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .like(User::getUsername, "o")<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .ge(User::getBalance, 1000);<br> &nbsp; &nbsp;// 2.查询<br> &nbsp; &nbsp;List&lt;User&gt; users = userMapper.selectList(wrapper);<br> &nbsp; &nbsp;users.forEach(System.out::println);<br>}</pre>



<h2 class="wp-block-heading">自定义SQL：</h2>



<p>MybatisPlus提供了自定义SQL功能，可以让我们利用Wrapper生成查询条件，再结合Mapper.xml编写SQL</p>



<h3 class="wp-block-heading">基本用法：</h3>



<p>实例如下：</p>



<pre class="wp-block-preformatted">@Test<br>void testCustomWrapper() {<br> &nbsp; &nbsp;// 1.准备自定义查询条件<br> &nbsp; &nbsp;List&lt;Long&gt; ids = List.of(1L, 2L, 4L);<br> &nbsp; &nbsp;QueryWrapper&lt;User&gt; wrapper = new QueryWrapper&lt;User&gt;().in("id", ids);<br>​<br> &nbsp; &nbsp;// 2.调用mapper的自定义方法，直接传递Wrapper<br> &nbsp; &nbsp;userMapper.deductBalanceByIds(200, wrapper);<br>}</pre>



<p>在UserMapper中自定义SQL：</p>



<pre class="wp-block-preformatted">public interface UserMapper extends BaseMapper&lt;User&gt; {<br> &nbsp; &nbsp;@Select("UPDATE user SET balance = balance - #{money} ${ew.customSqlSegment}")<br> &nbsp; &nbsp;void deductBalanceByIds(@Param("money") int money, @Param("ew") QueryWrapper&lt;User&gt; wrapper);<br>}</pre>



<h3 class="wp-block-heading">多表关联：</h3>



<p>理论上来讲MyBatisPlus是不支持多表查询的，我们可以利用Wrapper中自定义条件结合自定义SQL来实现多表查询的效果。</p>



<p>例如，要查询出所有收货地址在北京的并且用户id在1、2、4之中的用户 要是自己基于mybatis实现SQL：</p>



<pre class="wp-block-preformatted">&lt;select id="queryUserByIdAndAddr" resultType="com.itheima.mp.domain.po.User"&gt;<br> &nbsp; &nbsp;  SELECT *<br> &nbsp; &nbsp;  FROM user u<br> &nbsp; &nbsp;  INNER JOIN address a ON u.id = a.user_id<br> &nbsp; &nbsp;  WHERE u.id<br> &nbsp; &nbsp; &nbsp;&lt;foreach collection="ids" separator="," item="id" open="IN (" close=")"&gt;<br> &nbsp; &nbsp; &nbsp; &nbsp;  #{id}<br> &nbsp; &nbsp; &nbsp;&lt;/foreach&gt;<br> &nbsp; &nbsp;  AND a.city = #{city}<br> &nbsp;&lt;/select&gt;</pre>



<p>基于自定义SQL与Wrappe的结合，利用Wrapper来构建查询条件，手写SELECT及FROM部分，实现多表查询。</p>



<p>查询条件构建：</p>



<pre class="wp-block-preformatted">@Test<br>void testCustomJoinWrapper() {<br> &nbsp; &nbsp;// 1.准备自定义查询条件<br> &nbsp; &nbsp;QueryWrapper&lt;User&gt; wrapper = new QueryWrapper&lt;User&gt;()<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .in("u.id", List.of(1L, 2L, 4L))<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .eq("a.city", "北京");<br>​<br> &nbsp; &nbsp;// 2.调用mapper的自定义方法<br> &nbsp; &nbsp;List&lt;User&gt; users = userMapper.queryUserByWrapper(wrapper);<br>​<br> &nbsp; &nbsp;users.forEach(System.out::println);<br>}</pre>



<p>然后在UserMapper中自定义方法：</p>



<pre class="wp-block-preformatted">@Select("SELECT u.* FROM user u INNER JOIN address a ON u.id = a.user_id ${ew.customSqlSegment}")<br>List&lt;User&gt; queryUserByWrapper(@Param("ew")QueryWrapper&lt;User&gt; wrapper);</pre>



<p>或在<code>UserMapper.xml</code>中写SQL：</p>



<pre class="wp-block-preformatted">&lt;select id="queryUserByIdAndAddr" resultType="com.itheima.mp.domain.po.User"&gt;<br> &nbsp;  SELECT * FROM user u INNER JOIN address a ON u.id = a.user_id ${ew.customSqlSegment}<br>&lt;/select&gt;</pre>



<h2 class="wp-block-heading">Service接口：</h2>



<p>MybatisPlus提供了通用的Service接口及默认实现，封装了一些常用的service模板方法。 通用接口为IService，默认实现为ServiceImpl，其中封装的方法分为以下几类：</p>



<ul class="wp-block-list">
<li><code>save</code>：新增</li>



<li><code>remove</code>：删除</li>



<li><code>update</code>：更新</li>



<li><code>get</code>：查询单个结果</li>



<li><code>list</code>：查询集合结果</li>



<li><code>count</code>：计数</li>



<li><code>page</code>：分页查询</li>
</ul>



<h3 class="wp-block-heading">CRUD：</h3>



<p>基本的CRUD接口：</p>



<p>新增：</p>



<ul class="wp-block-list">
<li><code>save</code>是新增单个元素</li>



<li><code>saveBatch</code>是批量新增</li>



<li><code>saveOrUpdate</code>是根据id判断，如果数据存在就更新，不存在则新增</li>



<li><code>saveOrUpdateBatch</code>是批量的新增或修改</li>
</ul>



<p>删除：</p>



<ul class="wp-block-list">
<li><code>removeById</code>：根据id删除</li>



<li><code>removeByIds</code>：根据id批量删除</li>



<li><code>removeByMap</code>：根据Map中的键值对为条件删除</li>



<li><code>remove(Wrapper&lt;T&gt;)</code>：根据Wrapper条件删除</li>



<li><code>~~removeBatchByIds~~</code>：暂不支持</li>
</ul>



<p>修改：</p>



<ul class="wp-block-list">
<li><code>updateById</code>：根据id修改</li>



<li><code>update(Wrapper&lt;T&gt;)</code>：根据<code>UpdateWrapper</code>修改，<code>Wrapper</code>中包含<code>set</code>和<code>where</code>部分</li>



<li><code>update(T，Wrapper&lt;T&gt;)</code>：按照<code>T</code>内的数据修改与<code>Wrapper</code>匹配到的数据</li>



<li><code>updateBatchById</code>：根据id批量修改</li>
</ul>



<p>Get：</p>



<ul class="wp-block-list">
<li><code>getById</code>：根据id查询1条数据</li>



<li><code>getOne(Wrapper&lt;T&gt;)</code>：根据<code>Wrapper</code>查询1条数据</li>



<li><code>getBaseMapper</code>：获取<code>Service</code>内的<code>BaseMapper</code>实现，某些时候需要直接调用<code>Mapper</code>内的自定义<code>SQL</code>时可以用这个方法获取到<code>Mapper</code></li>
</ul>



<p>List：</p>



<ul class="wp-block-list">
<li><code>listByIds</code>：根据id批量查询</li>



<li><code>list(Wrapper&lt;T&gt;)</code>：根据Wrapper条件查询多条数据</li>



<li><code>list()</code>：查询所有</li>
</ul>



<p>Count：</p>



<ul class="wp-block-list">
<li><code>count()</code>：统计所有数量</li>



<li><code>count(Wrapper&lt;T&gt;)</code>：统计符合<code>Wrapper</code>条件的数据数量</li>
</ul>



<p>getBaseMapper： 当我们在service中要调用Mapper中自定义SQL时，就必须获取service对应的Mapper，就可以通过这个方法：</p>



<h3 class="wp-block-heading">基本用法：</h3>



<p>由于<code>Service</code>中经常需要定义与业务有关的自定义方法，因此我们不能直接使用<code>IService</code>，而是自定义<code>Service</code>接口，然后继承<code>IService</code>以拓展方法。同时，让自定义的<code>Service实现类</code>继承<code>ServiceImpl</code>，这样就不用自己实现<code>IService</code>中的接口了。</p>



<p>首先，定义<code>IUserService</code>，继承<code>IService</code>：</p>



<pre class="wp-block-preformatted">public interface IUserService extends IService&lt;User&gt; {<br> &nbsp; &nbsp;// 拓展自定义方法<br>}</pre>



<p>然后，编写<code>UserServiceImpl</code>类，继承<code>ServiceImpl</code>，实现<code>UserService</code>：</p>



<pre class="wp-block-preformatted">@Service<br>public class UserServiceImpl extends ServiceImpl&lt;UserMapper, User&gt; implements IUserService {<br>}</pre>



<p>接下来，我们快速实现下面4个接口：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th><strong>编号</strong></th><th><strong>接口</strong></th><th><strong>请求方式</strong></th><th><strong>请求路径</strong></th><th><strong>请求参数</strong></th><th><strong>返回值</strong></th></tr></thead><tbody><tr><td>1</td><td>新增用户</td><td>POST</td><td>/users</td><td>用户表单实体</td><td>无</td></tr><tr><td>2</td><td>删除用户</td><td>DELETE</td><td>/users/{id}</td><td>用户id</td><td>无</td></tr><tr><td>3</td><td>根据id查询用户</td><td>GET</td><td>/users/{id}</td><td>用户id</td><td>用户VO</td></tr><tr><td>4</td><td>根据id批量查询</td><td>GET</td><td>/users</td><td>用户id集合</td><td>用户VO集合</td></tr></tbody></table></figure>



<p>然后，接口需要两个实体：</p>



<ul class="wp-block-list">
<li>UserFormDTO：代表新增时的用户表单</li>



<li>UserVO：代表查询的返回结果</li>
</ul>



<p>首先是UserFormDTO：</p>



<pre class="wp-block-preformatted">@Data<br>@ApiModel(description = "用户表单实体")<br>public class UserFormDTO {<br>​<br> &nbsp; &nbsp;@ApiModelProperty("id")<br> &nbsp; &nbsp;private Long id;<br>​<br> &nbsp; &nbsp;@ApiModelProperty("用户名")<br> &nbsp; &nbsp;private String username;<br>​<br> &nbsp; &nbsp;@ApiModelProperty("密码")<br> &nbsp; &nbsp;private String password;<br>​<br> &nbsp; &nbsp;@ApiModelProperty("注册手机号")<br> &nbsp; &nbsp;private String phone;<br>​<br> &nbsp; &nbsp;@ApiModelProperty("详细信息，JSON风格")<br> &nbsp; &nbsp;private String info;<br>​<br> &nbsp; &nbsp;@ApiModelProperty("账户余额")<br> &nbsp; &nbsp;private Integer balance;<br>}</pre>



<p>然后是UserVO：</p>



<pre class="wp-block-preformatted">@Data<br>@ApiModel(description = "用户VO实体")<br>public class UserVO {<br> &nbsp; &nbsp;<br> &nbsp; &nbsp;@ApiModelProperty("用户id")<br> &nbsp; &nbsp;private Long id;<br> &nbsp; &nbsp;<br> &nbsp; &nbsp;@ApiModelProperty("用户名")<br> &nbsp; &nbsp;private String username;<br> &nbsp; &nbsp;<br> &nbsp; &nbsp;@ApiModelProperty("详细信息")<br> &nbsp; &nbsp;private String info;<br>​<br> &nbsp; &nbsp;@ApiModelProperty("使用状态（1正常 2冻结）")<br> &nbsp; &nbsp;private Integer status;<br> &nbsp; &nbsp;<br> &nbsp; &nbsp;@ApiModelProperty("账户余额")<br> &nbsp; &nbsp;private Integer balance;<br>}</pre>



<p>最后，按照Restful风格编写Controller接口方法：</p>



<pre class="wp-block-preformatted">@Api(tags = "用户管理接口")<br>@RequiredArgsConstructor<br>@RestController<br>@RequestMapping("users")<br>public class UserController {<br>​<br> &nbsp; &nbsp;private final IUserService userService;<br>​<br> &nbsp; &nbsp;@PostMapping<br> &nbsp; &nbsp;@ApiOperation("新增用户")<br> &nbsp; &nbsp;public void saveUser(@RequestBody UserFormDTO userFormDTO){<br> &nbsp; &nbsp; &nbsp; &nbsp;// 1.转换DTO为PO<br> &nbsp; &nbsp; &nbsp; &nbsp;User user = BeanUtil.copyProperties(userFormDTO, User.class);<br> &nbsp; &nbsp; &nbsp; &nbsp;// 2.新增<br> &nbsp; &nbsp; &nbsp; &nbsp;userService.save(user);<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;@DeleteMapping("/{id}")<br> &nbsp; &nbsp;@ApiOperation("删除用户")<br> &nbsp; &nbsp;public void removeUserById(@PathVariable("id") Long userId){<br> &nbsp; &nbsp; &nbsp; &nbsp;userService.removeById(userId);<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;@GetMapping("/{id}")<br> &nbsp; &nbsp;@ApiOperation("根据id查询用户")<br> &nbsp; &nbsp;public UserVO queryUserById(@PathVariable("id") Long userId){<br> &nbsp; &nbsp; &nbsp; &nbsp;// 1.查询用户<br> &nbsp; &nbsp; &nbsp; &nbsp;User user = userService.getById(userId);<br> &nbsp; &nbsp; &nbsp; &nbsp;// 2.处理vo<br> &nbsp; &nbsp; &nbsp; &nbsp;return BeanUtil.copyProperties(user, UserVO.class);<br> &nbsp;  }<br>​<br> &nbsp; &nbsp;@GetMapping<br> &nbsp; &nbsp;@ApiOperation("根据id集合查询用户")<br> &nbsp; &nbsp;public List&lt;UserVO&gt; queryUserByIds(@RequestParam("ids") List&lt;Long&gt; ids){<br> &nbsp; &nbsp; &nbsp; &nbsp;// 1.查询用户<br> &nbsp; &nbsp; &nbsp; &nbsp;List&lt;User&gt; users = userService.listByIds(ids);<br> &nbsp; &nbsp; &nbsp; &nbsp;// 2.处理vo<br> &nbsp; &nbsp; &nbsp; &nbsp;return BeanUtil.copyToList(users, UserVO.class);<br> &nbsp;  }<br>}</pre>



<p>可以看到上述接口都直接在controller即可实现，无需编写任何service代码，非常方便。</p>



<p>不过，一些带有业务逻辑的接口则需要在service中自定义实现了。例如下面的需求：</p>



<ul class="wp-block-list">
<li>根据id扣减用户余额</li>
</ul>



<p>这看起来是个简单修改功能，只要修改用户余额即可。但这个业务包含一些业务逻辑处理：</p>



<ul class="wp-block-list">
<li>判断用户状态是否正常</li>



<li>判断用户余额是否充足</li>
</ul>



<p>这些业务逻辑都要在service层来做，另外更新余额需要自定义SQL，要在mapper中来实现。因此，我们除了要编写controller以外，具体的业务还要在service和mapper中编写。</p>



<p>首先在UserController中定义一个方法：</p>



<pre class="wp-block-preformatted">@PutMapping("{id}/deduction/{money}")<br>@ApiOperation("扣减用户余额")<br>public void deductBalance(@PathVariable("id") Long id, @PathVariable("money")Integer money){<br> &nbsp; &nbsp;userService.deductBalance(id, money);<br>}</pre>



<p>然后是UserService接口：</p>



<pre class="wp-block-preformatted">public interface IUserService extends IService&lt;User&gt; {<br> &nbsp; &nbsp;void deductBalance(Long id, Integer money);<br>}</pre>



<p>最后是UserServiceImpl实现类：</p>



<pre class="wp-block-preformatted">@Service<br>public class UserServiceImpl extends ServiceImpl&lt;UserMapper, User&gt; implements IUserService {<br> &nbsp; &nbsp;@Override<br> &nbsp; &nbsp;public void deductBalance(Long id, Integer money) {<br> &nbsp; &nbsp; &nbsp; &nbsp;// 1.查询用户<br> &nbsp; &nbsp; &nbsp; &nbsp;User user = getById(id);<br> &nbsp; &nbsp; &nbsp; &nbsp;// 2.判断用户状态<br> &nbsp; &nbsp; &nbsp; &nbsp;if (user == null || user.getStatus() == 2) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new RuntimeException("用户状态异常");<br> &nbsp; &nbsp; &nbsp;  }<br> &nbsp; &nbsp; &nbsp; &nbsp;// 3.判断用户余额<br> &nbsp; &nbsp; &nbsp; &nbsp;if (user.getBalance() &lt; money) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new RuntimeException("用户余额不足");<br> &nbsp; &nbsp; &nbsp;  }<br> &nbsp; &nbsp; &nbsp; &nbsp;// 4.扣减余额<br> &nbsp; &nbsp; &nbsp; &nbsp;baseMapper.deductMoneyById(id, money);<br> &nbsp;  }<br>}</pre>



<p>最后是mapper：</p>



<pre class="wp-block-preformatted">@Update("UPDATE user SET balance = balance - #{money} WHERE id = #{id}")<br>void deductMoneyById(@Param("id") Long id, @Param("money") Integer money);</pre>



<h3 class="wp-block-heading">Lambda：</h3>



<p>IService中提供了Lambda功能来简化复杂查询及更新功能：</p>



<p>案例一：实现一个根据复杂条件查询用户的接口，查询条件如下：</p>



<ul class="wp-block-list">
<li>name：用户名关键字，可以为空</li>



<li>status：用户状态，可以为空</li>



<li>minBalance：最小余额，可以为空</li>



<li>maxBalance：最大余额，可以为空</li>
</ul>



<p>可以理解成一个用户的后台管理界面，管理员可以自己选择条件来筛选用户，因此上述条件不一定存在，需要做判断。</p>



<p>我们首先需要定义一个查询条件实体，UserQuery实体：</p>



<pre class="wp-block-preformatted">package com.itheima.mp.domain.query;<br>​<br>import io.swagger.annotations.ApiModel;<br>import io.swagger.annotations.ApiModelProperty;<br>import lombok.Data;<br>​<br>@Data<br>@ApiModel(description = "用户查询条件实体")<br>public class UserQuery {<br> &nbsp; &nbsp;@ApiModelProperty("用户名关键字")<br> &nbsp; &nbsp;private String name;<br> &nbsp; &nbsp;@ApiModelProperty("用户状态：1-正常，2-冻结")<br> &nbsp; &nbsp;private Integer status;<br> &nbsp; &nbsp;@ApiModelProperty("余额最小值")<br> &nbsp; &nbsp;private Integer minBalance;<br> &nbsp; &nbsp;@ApiModelProperty("余额最大值")<br> &nbsp; &nbsp;private Integer maxBalance;<br>}</pre>



<p>接下来我们在UserController中定义一个controller方法：</p>



<pre class="wp-block-preformatted">@GetMapping("/list")<br>@ApiOperation("根据id集合查询用户")<br>public List&lt;UserVO&gt; queryUsers(UserQuery query){<br> &nbsp; &nbsp;// 1.组织条件<br> &nbsp; &nbsp;String username = query.getName();<br> &nbsp; &nbsp;Integer status = query.getStatus();<br> &nbsp; &nbsp;Integer minBalance = query.getMinBalance();<br> &nbsp; &nbsp;Integer maxBalance = query.getMaxBalance();<br> &nbsp; &nbsp;LambdaQueryWrapper&lt;User&gt; wrapper = new QueryWrapper&lt;User&gt;().lambda()<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .like(username != null, User::getUsername, username)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .eq(status != null, User::getStatus, status)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .ge(minBalance != null, User::getBalance, minBalance)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .le(maxBalance != null, User::getBalance, maxBalance);<br> &nbsp; &nbsp;// 2.查询用户<br> &nbsp; &nbsp;List&lt;User&gt; users = userService.list(wrapper);<br> &nbsp; &nbsp;// 3.处理vo<br> &nbsp; &nbsp;return BeanUtil.copyToList(users, UserVO.class);<br>}</pre>



<p>在组织查询条件的时候加入username != null这样的参数，意思就是当条件成立时才会添加这个查询条件</p>



<p>不过，上述条件构建的代码太麻烦了。 因此Service中对<code>LambdaQueryWrapper</code>和<code>LambdaUpdateWrapper</code>的用法进一步做了简化。我们无需自己通过<code>new</code>的方式来创建<code>Wrapper</code>，而是直接调用<code>lambdaQuery</code>和<code>lambdaUpdate</code>方法：</p>



<p>基于Lambda查询：</p>



<pre class="wp-block-preformatted">@GetMapping("/list")<br>@ApiOperation("根据id集合查询用户")<br>public List&lt;UserVO&gt; queryUsers(UserQuery query){<br> &nbsp; &nbsp;// 1.组织条件<br> &nbsp; &nbsp;String username = query.getName();<br> &nbsp; &nbsp;Integer status = query.getStatus();<br> &nbsp; &nbsp;Integer minBalance = query.getMinBalance();<br> &nbsp; &nbsp;Integer maxBalance = query.getMaxBalance();<br> &nbsp; &nbsp;// 2.查询用户<br> &nbsp; &nbsp;List&lt;User&gt; users = userService.lambdaQuery()<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .like(username != null, User::getUsername, username)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .eq(status != null, User::getStatus, status)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .ge(minBalance != null, User::getBalance, minBalance)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .le(maxBalance != null, User::getBalance, maxBalance)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .list();<br> &nbsp; &nbsp;// 3.处理vo<br> &nbsp; &nbsp;return BeanUtil.copyToList(users, UserVO.class);<br>}</pre>



<p>可以发现lambdaQuery方法中除了可以构建条件，还需要在链式编程的最后添加一个<code>list()</code>，这是在告诉MP我们的调用结果需要是一个list集合。这里不仅可以用<code>list()</code>，可选的方法有：</p>



<ul class="wp-block-list">
<li><code>.one()</code>：最多1个结果</li>



<li><code>.list()</code>：返回集合结果</li>



<li><code>.count()</code>：返回计数结果</li>
</ul>



<p>MybatisPlus会根据链式编程的最后一个方法来判断最终的返回结果。</p>



<p>与lambdaQuery方法类似，IService中的lambdaUpdate方法可以非常方便的实现复杂更新业务。</p>



<p>例如下面的需求：</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>需求：改造根据id修改用户余额的接口，要求如下</p>



<ul class="wp-block-list">
<li>如果扣减后余额为0，则将用户status修改为冻结状态（2）</li>
</ul>
</blockquote>



<p>也就是说我们在扣减用户余额时，需要对用户剩余余额做出判断，如果发现剩余余额为0，则应该将status修改为2，这就是说update语句的set部分是动态的。</p>



<p>实现如下：</p>



<pre class="wp-block-preformatted">@Override<br>@Transactional<br>public void deductBalance(Long id, Integer money) {<br> &nbsp; &nbsp;// 1.查询用户<br> &nbsp; &nbsp;User user = getById(id);<br> &nbsp; &nbsp;// 2.校验用户状态<br> &nbsp; &nbsp;if (user == null || user.getStatus() == 2) {<br> &nbsp; &nbsp; &nbsp; &nbsp;throw new RuntimeException("用户状态异常！");<br> &nbsp;  }<br> &nbsp; &nbsp;// 3.校验余额是否充足<br> &nbsp; &nbsp;if (user.getBalance() &lt; money) {<br> &nbsp; &nbsp; &nbsp; &nbsp;throw new RuntimeException("用户余额不足！");<br> &nbsp;  }<br> &nbsp; &nbsp;// 4.扣减余额 update tb_user set balance = balance - ?<br> &nbsp; &nbsp;int remainBalance = user.getBalance() - money;<br> &nbsp; &nbsp;lambdaUpdate()<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .set(User::getBalance, remainBalance) // 更新余额<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .set(remainBalance == 0, User::getStatus, 2) // 动态判断，是否更新status<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .eq(User::getId, id)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .eq(User::getBalance, user.getBalance()) // 乐观锁<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  .update();<br>}</pre>



<h3 class="wp-block-heading">批量新增：</h3>



<p>IService中批量新增功能使用:</p>



<p>MybatisPlus批量处理：</p>



<pre class="wp-block-preformatted">@Test<br>void testSaveBatch() {<br> &nbsp; &nbsp;// 准备10万条数据<br> &nbsp; &nbsp;List&lt;User&gt; list = new ArrayList&lt;&gt;(1000);<br> &nbsp; &nbsp;long b = System.currentTimeMillis();<br> &nbsp; &nbsp;for (int i = 1; i &lt;= 100000; i++) {<br> &nbsp; &nbsp; &nbsp; &nbsp;list.add(buildUser(i));<br> &nbsp; &nbsp; &nbsp; &nbsp;// 每1000条批量插入一次<br> &nbsp; &nbsp; &nbsp; &nbsp;if (i % 1000 == 0) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;userService.saveBatch(list);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;list.clear();<br> &nbsp; &nbsp; &nbsp;  }<br> &nbsp;  }<br> &nbsp; &nbsp;long e = System.currentTimeMillis();<br> &nbsp; &nbsp;System.out.println("耗时：" + (e - b));<br>}<br>​<br>private User buildUser(int i) {<br> &nbsp; &nbsp;User user = new User();<br> &nbsp; &nbsp;user.setUsername("user_" + i);<br> &nbsp; &nbsp;user.setPassword("123");<br> &nbsp; &nbsp;user.setPhone("" + (18688190000L + i));<br> &nbsp; &nbsp;user.setBalance(2000);<br> &nbsp; &nbsp;user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");<br> &nbsp; &nbsp;user.setCreateTime(LocalDateTime.now());<br> &nbsp; &nbsp;user.setUpdateTime(user.getCreateTime());<br> &nbsp; &nbsp;return user;<br>}</pre>



<p>要得到最佳性能，需将多条SQL合并为一条，如下所示：</p>



<pre class="wp-block-preformatted">INSERT INTO user ( username, password, phone, info, balance, create_time, update_time )<br>VALUES <br>(user_1, 123, 18688190001, "", 2000, 2023-07-01, 2023-07-01),<br>(user_2, 123, 18688190002, "", 2000, 2023-07-01, 2023-07-01),<br>(user_3, 123, 18688190003, "", 2000, 2023-07-01, 2023-07-01),<br>(user_4, 123, 18688190004, "", 2000, 2023-07-01, 2023-07-01);</pre>



<p>做法：</p>



<p>在MySQL的客户端连接参数中有这样的一个参数：<code>rewriteBatchedStatements</code>。是重写批处理的<code>statement</code>语句。这个参数的默认值是false，我们需要修改连接参数，将其配置为true</p>



<p>修改项目中的application.yml文件，在jdbc的url后面添加参数</p>



<pre class="wp-block-preformatted">&amp;rewriteBatchedStatements=true</pre>



<pre class="wp-block-preformatted">spring:<br>  datasource:<br> &nbsp;  url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&amp;characterEncoding=UTF-8&amp;autoReconnect=true&amp;serverTimezone=Asia/Shanghai&amp;rewriteBatchedStatements=true</pre>



<p><a href="#top">返回顶部</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.qiqin-chang.cn/mybatisplus-%e6%8c%81%e4%b9%85%e5%b1%82%e6%a1%86%e6%9e%b6/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
