代码生成
方式一:官方jar
为了简化MyBatis的编写,官方推出了一个工具"mybatis-generator",Java编写的,通过这个工具可以生成数据库表对应的实体类、Mapper接口以及Mapper映射文件。
官网:
http://mybatis.org/generator/
快速入门指南:
http://mybatis.org/generator/quickstart.html
我们这里就是使用从命令提示符运行MyBatis Generator。
您必须创建XML配置文件才能从命令行运行MBG。如果文件名为“ generatorConfig.xml”,则以下任何命令行将运行MBG:
java -jar mybatis-generator-core-xxxjar -configfile generatorConfig.xml
java -jar mybatis-generator-core-xxxjar -configfile generatorConfig.xml -overwrite
参数 |
解释 |
-configfile 文件名 (必需) |
指定配置文件的名称。 |
-overwrite(可选) |
如果指定,则如果发现现有Java文件的名称与生成的文件的名称相同,则现有Java文件将被覆盖。如果未指定,并且已经存在与生成文件同名的Java文件,则MBG会将新生成的Java文件以唯一名称(例如MyClass.java.1,MyClass.java.2,等等。)。 |
jar包是一系列class和资源文件的组合包,jar包如果配置了main函数所在的执行类,jar包是可以直接运行在虚拟机上的。
但是通过上面的方式,自动创建的pojo、mapper.java、mapper.xml没有在IDEA环境中,需要将生成的文件拷贝到项目中,不是特别方便。
上面的方式,具有通用的优点,任何IDE开发工具都可以使用。
方式二:IDEA
如果是IDEA,那么Easy Code插件可以解决这个问题。
首先需要在IDEA中连接数据库,下面是IDEA中连接MySQL数据库的驱动
1、使用Easy Code:
效果:如左侧所示。
2、使用mybatis-generate tool;
使用第二种的效果:
测试成功。
插件及其应用(PageHelper)
查询数据的时候,会遇到分页的问题(分页就是将满足条件的数据,按照每一页多少条这样的数据限定要求进行显示,程序中的查询大部分都需要使用到分页)。
分页我们分为
前端
前端需要分页的 数据(总条数,总页数,当前第几页[计算有没有上一页,有无下一页...],当前页码的数据[list])
显示分页操作条【栏】
挺麻烦的【前端可以使用分页插件】
后台
后台要编写两条sql
一条是查询全部数据【需要总条数】
一条sql查询当前页码的数据
service 或者 工具类中,计算,通过总条数以及每页条数,计算共有多少页....
数据库
数据库要有分页的sql语句,
mysql limit关键词【最简单的】
oracle rownum伪劣【最麻烦】
sqlserver top【子查询】
通过mybatis的分页插件,大大简化分页的sql以及分页的逻辑封装部分。
类似于Java Web中的过滤器【过滤器就是一个筛子,也就是说客户端请求服务器端资源,比如请求xxxservlet,过滤器就是在访问xxxservlet之前,会拦截客户端请求。相应地,之前servlet中返回数据,到客户端,现在返回数据之后,还要经过过滤器,才会到客户端】;
MyBatis中有一个接口,叫做拦截器Interceptor,允许我们定制更加灵活的程序,比如通过拦截器,可以拦截mybatis执行过程中一些重要的组件和方法。
比如通过编写拦截器,就可以得到程序运行过程中给的sql语句,并且我们可以修改sql语句。mybatis开放了这样的功能。
pageHelper就是利用了mybatis中提供的这个拦截器功能,可以对分页进行大大的简化。
官网:https://pagehelper.github.io/
如果你也在用 MyBatis,建议尝试该分页插件,这一定是最方便使用的分页插件。分页插件支持任何复杂的单表、多表分页。
使用方式:https://pagehelper.github.io/docs/howtouse/
1、引入分页插件
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
2、配置拦截器插件
特别注意,新版拦截器是 com.github.pagehelper.PageInterceptor
。 com.github.pagehelper.PageHelper
现在是一个特殊的 dialect
实现类,是分页插件的默认实现类,提供了和以前相同的用法。
2.1、在MyBatis配置文件中配置拦截器
<!--
plugins在配置文件中的位置必须符合要求,否则会报错,顺序如下:
properties?, settings?,
typeAliases?, typeHandlers?,
objectFactory?,objectWrapperFactory?,
plugins?,
environments?, databaseIdProvider?, mappers?
-->
<plugins>
<!-- com.github.pagehelper为PageHelper类所在包名 -->
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->
<property name="param1" value="value1"/>
</plugin>
</plugins>
3、使用
为分页查询新建一张表page,自动生成model、mapper.java、mapper.xml文件,然后添加100条数据。
@Data
public class Page implements Serializable {
private Integer pid;
private String pname;
private Integer pcount;
private Double pprice;
private static final long serialVersionUID = 1L;
}
为表中初始化100条数据
@Test
public void initData() {
try (SqlSession sqlSession = factory.openSession()) {
PageMapper mapper = sqlSession.getMapper(PageMapper.class);
for (int i = 1; i <= 100; i++) {
Page page = new Page();
page.setPname("java" + i);
page.setPcount(i);
page.setPprice(i + 0.1);
mapper.insertSelective(page);
}
sqlSession.commit();
}
}
全查测试:
//带查询条件的分页的查询方法
List<Page> select(Page page);
<resultMap id="BaseResultMap" type="org.westos.model.Page">
<id column="pid" jdbcType="INTEGER" property="pid"/>
<result column="pname" jdbcType="VARCHAR" property="pname"/>
<result column="pcount" jdbcType="INTEGER" property="pcount"/>
<result column="pprice" jdbcType="FLOAT" property="pprice"/>
</resultMap>
<sql id="Base_Column_List">
pid, pname, pcount, pprice
</sql>
<select id="select" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from page
<where>
<if test="pid != null">
and pid = #{pid}
</if>
<if test="pname != null">
and pname like concat('%', #{pname}, '%')
</if>
<if test="pcount != null">
and pcount = #{pcount}
</if>
<if test="pprice != null">
and pprice = #{pprice}
</if>
</where>
</select>
//全查测试
@Test
public void select1() {
try (SqlSession sqlSession = factory.openSession()) {
PageMapper mapper = sqlSession.getMapper(PageMapper.class);
List<Page> select = mapper.select(null);
System.out.println(JSON.toJSONString(select, true));
}
}
带参数的全查测试:
//全查测试,带参数
@Test
public void select2() {
try (SqlSession sqlSession = factory.openSession()) {
PageMapper mapper = sqlSession.getMapper(PageMapper.class);
Page page = new Page();
page.setPname("java2");
List<Page> select = mapper.select(page);
System.out.println(select.size());
//11
}
}
全查测试,带分页:
//全查测试,带分页
@Test
public void select3() {
try (SqlSession sqlSession = factory.openSession()) {
PageMapper mapper = sqlSession.getMapper(PageMapper.class);
//配置分页,需要两个参数:1、pageNum第几页 2、pageSize页的大小
PageHelper.startPage(2, 10);
//第二页,查10条
//limit (pageNum-1)*size, size
//limit 0,10
//limit 10,10
//limit 20,10
List<Page> select = mapper.select(null);
System.out.println(select.size());
}
}
==> Preparing: SELECT count(0) FROM page
==> Parameters:
<== Columns: count(0)
<== Row: 100
<== Total: 1
==> Preparing: select pid, pname, pcount, pprice from page LIMIT ?, ?
==> Parameters: 10(Long), 10(Integer)
<== Columns: pid, pname, pcount, pprice
<== Row: 11, java11, 11, 11.1
<== Row: 12, java12, 12, 12.1
<== Row: 13, java13, 13, 13.1
<== Row: 14, java14, 14, 14.1
<== Row: 15, java15, 15, 15.1
<== Row: 16, java16, 16, 16.1
<== Row: 17, java17, 17, 17.1
<== Row: 18, java18, 18, 18.1
<== Row: 19, java19, 19, 19.1
<== Row: 20, java20, 20, 20.1
<== Total: 10
10
全查测试,带条件,带分页
//全查测试,带条件,带分页
@Test
public void select4() {
try (SqlSession sqlSession = factory.openSession()) {
PageMapper mapper = sqlSession.getMapper(PageMapper.class);
PageHelper.startPage(1, 5);
Page page = new Page();
page.setPname("java1");
List<Page> select = mapper.select(page);
System.out.println(JSON.toJSONString(select, true));
PageHelper.startPage(2, 5);
select = mapper.select(page);
System.out.println(JSON.toJSONString(select, true));
}
}
==> Preparing: SELECT count(0) FROM page WHERE pname LIKE concat('%', ?, '%')
==> Parameters: java1(String)
<== Columns: count(0)
<== Row: 12
<== Total: 1
==> Preparing: select pid, pname, pcount, pprice from page WHERE pname like concat('%', ?, '%') LIMIT ?
==> Parameters: java1(String), 5(Integer)
<== Columns: pid, pname, pcount, pprice
<== Row: 1, java1, 1, 1.1
<== Row: 10, java10, 10, 10.1
<== Row: 11, java11, 11, 11.1
<== Row: 12, java12, 12, 12.1
<== Row: 13, java13, 13, 13.1
<== Total: 5
[
{
"pcount":1,
"pid":1,
"pname":"java1",
"pprice":1.1
},
{
"pcount":10,
"pid":10,
"pname":"java10",
"pprice":10.1
},
{
"pcount":11,
"pid":11,
"pname":"java11",
"pprice":11.1
},
{
"pcount":12,
"pid":12,
"pname":"java12",
"pprice":12.1
},
{
"pcount":13,
"pid":13,
"pname":"java13",
"pprice":13.1
}
]
==> Preparing: select pid, pname, pcount, pprice from page WHERE pname like concat('%', ?, '%') LIMIT ?, ?
==> Parameters: java1(String), 5(Long), 5(Integer)
<== Columns: pid, pname, pcount, pprice
<== Row: 14, java14, 14, 14.1
<== Row: 15, java15, 15, 15.1
<== Row: 16, java16, 16, 16.1
<== Row: 17, java17, 17, 17.1
<== Row: 18, java18, 18, 18.1
<== Total: 5
[
{
"pcount":14,
"pid":14,
"pname":"java14",
"pprice":14.1
},
{
"pcount":15,
"pid":15,
"pname":"java15",
"pprice":15.1
},
{
"pcount":16,
"pid":16,
"pname":"java16",
"pprice":16.1
},
{
"pcount":17,
"pid":17,
"pname":"java17",
"pprice":17.1
},
{
"pcount":18,
"pid":18,
"pname":"java18",
"pprice":18.1
}
]
全查测试,带分页,带分页数据的封装功能
//全查测试,带分页,带分页数据的封装功能
@Test
public void select5() {
try (SqlSession sqlSession = factory.openSession()) {
PageMapper mapper = sqlSession.getMapper(PageMapper.class);
//在查询之前
PageHelper.startPage(1, 10);
List<Page> select = mapper.select(null);
//分页信息封装类,通常写在查询之后
PageInfo<Page> pageInfo = new PageInfo<>(select);
System.out.println(JSON.toJSONString(pageInfo, true));
}
}
{
"endRow":10,
"hasNextPage":true,
"hasPreviousPage":false,
"isFirstPage":true,
"isLastPage":false,
"list":[
{
"pcount":1,
"pid":1,
"pname":"java1",
"pprice":1.1
},
{
"pcount":2,
"pid":2,
"pname":"java2",
"pprice":2.1
},
{
"pcount":3,
"pid":3,
"pname":"java3",
"pprice":3.1
},
{
"pcount":4,
"pid":4,
"pname":"java4",
"pprice":4.1
},
{
"pcount":5,
"pid":5,
"pname":"java5",
"pprice":5.1
},
{
"pcount":6,
"pid":6,
"pname":"java6",
"pprice":6.1
},
{
"pcount":7,
"pid":7,
"pname":"java7",
"pprice":7.1
},
{
"pcount":8,
"pid":8,
"pname":"java8",
"pprice":8.1
},
{
"pcount":9,
"pid":9,
"pname":"java9",
"pprice":9.1
},
{
"pcount":10,
"pid":10,
"pname":"java10",
"pprice":10.1
}
],
"navigateFirstPage":1,
"navigateLastPage":8,
"navigatePages":8,
"navigatepageNums":[1,2,3,4,5,6,7,8],
"nextPage":2,
"pageNum":1,
"pageSize":10,
"pages":10,
"prePage":0,
"size":10,
"startRow":1,
"total":100
}
在说详细的原理:
如何自定义mybatis的拦截器【了解,mybatis提供插件这样的功能是为了更加灵活的执行一些操作,允许程序员查看或者操控mybatis运行的细节】
第一步:实现Interceptor接口
public interface Interceptor {
//拦截之后需要执行的方法
Object intercept(Invocation invocation) throws Throwable;
//返回代理对象
Object plugin(Object target);
//设置拦截器 运行的一些参数
void setProperties(Properties properties);
}
package org.westos.util;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import java.sql.Connection;
import java.util.Properties;
/**
* @author lwj
* @date 2020/9/20 9:17
*/
@Intercepts({
@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class MyBatisInterceptor implements Interceptor {
/*
* MyBatis允许拦截
* 1、Executor执行器(SqlSession持有执行器)
* 2、SQL语句执行 StatementHandler 拦截sql语句
* 3、参数
* 4、结果
* (1)需要用@Intercepts注解来指定
* (2)将该拦截器注册到mybatis-config.xml
* */
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler sh = (StatementHandler) invocation.getTarget();
MetaObject mo = SystemMetaObject.forObject(sh);
//获得了运算后的sql
Object value = mo.getValue("delegate.boundSql.sql");
System.out.println("MyBatisInterceptor-->>" + value);
return invocation.proceed();
}
@Override
public Object plugin(Object o) {
return Plugin.wrap(o,this);
}
@Override
public void setProperties(Properties properties) {
}
}
第二步:配置拦截器
<plugins>
<!-- com.github.pagehelper为PageHelper类所在包名 -->
<!--<plugin interceptor="com.github.pagehelper.PageInterceptor">
</plugin>-->
<plugin interceptor="org.westos.util.MyBatisInterceptor"/>
</plugins>
测试,随意测试Mapper中的方法,在控制台中均可以查看到 mybatis运行过程中的sql语句
@Test
public void testSelectByPrimaryKey() {
try (SqlSession sqlSession = factory.openSession()) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.selectByPrimaryKey(1);
System.out.println(JSON.toJSONString(user,true));
}
}
MyBatisInterceptor-->>select
uid, uname, upassword, u_nickname
from user
where `uid` = ?