目录
10. 逆向工程:mybatis的代码生成器--generator
1. mybatis的介绍:
MyBatis 是一款优秀的持久层Dao框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XM L 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Java实体类)映射成数据库中的 记录.
2. 为什么使用mybatis框架.
可以简化jdbc的操作以及占位符赋值以及查询结果集的封装。
3. 如何使用mybatis.
3.1 引入mybatis和mysql的jar包
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
3.2 创建数据库和表
DROP TABLE IF EXISTS `tbl_user`;
CREATE TABLE `tbl_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255),
`email` varchar(255)
);
3.3 创建实体类
package com.zpb.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int id;
private String name;
private String email;
}
3.4 创建mybatis的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<!--数据源的配置:name的值固定 value的值要根据客户自己修改-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!--注意:==把映射文件注册到配置文件上== mybatis.xml上-->
<mappers>
<!--resource:引用资源文中的映射文件 url:网络上的映射文件-->
<mapper resource="mapper/UserMapper.xml" />
</mappers>
</configuration>
3.5 创建一个dao接口并定义自己需要的方法。
public interface UserDao {
/**
* 查询所有
* @return
*/
public List<User> findAll();
}
3.6 创建mybatis和数据库的映射文件
<?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">
<!--namespace:命名空间
企业开发模式命名要与dao的路径一致
-->
<mapper namespace="com.zpb.dao.UserDao">
<!--查询
select标签用于查询的标签
id:标签的唯一标识, id和dao中的方法名必须一致
resultType: 定义返回的类型 把sql查询的结果封装到哪个实体类中
#{id}===表示占位符等价于? 这是mybatis框架的语法
-->
<select id="findAll" resultType="com.zpb.entity.User">
select * from tbl_user
</select>
</mapper>
3.7 测试mybatis
public class Test01 {
public static void main(String[] args) throws Exception {
@Test
public void testFindAll()throws Exception{
//1.读取mybatis配置文件的内容----未来不需要写tomcat 解析配置文件
Reader reader = Resources.getResourceAsReader("mybatis.xml");
//2. 获取SqlSessionFactory对象
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
//3. 获取SqlSession对象----封装了对数据库操作的各种方法
SqlSession session = sessionFactory.openSession();
//4. 获取相应接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
List<User> list = userDao.findAll();
System.out.println(list);
session.close();
}
}
4. mybatis一些优化
4.1 为实体类起别名
mybatis.xml配置文件
<typeAliases>
<!--单独为某个实体类起别名 -->
<typeAlias type="com.zpb.entity.User" alias="u"/>
<!--为指定包下的实体类起别名该别名就是实体类名-->
<package name="com.zpb.entity"/>
</typeAliases>
4.2 添加sql日志
(1)添加日志的jar.
<!--log4f-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
(2) 添加日志的文件配置--log4j.properties
简略:
log4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
详细:
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=D:/qy151/log/qy151.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
4.3 安装mybatis插件
Free Mybatis Tool或者MybatisX
作用: 检查dao和映射文件是否匹配
4.4 lombok插件
在实体类中加入注释,它可以帮你生成实体类的get和set方法 而且可以帮你生成构造方法。重写toString方法
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int id;
private String name;
private String email;
}
5. 传递多个参数
我们在dao接口中某些方法可能需要传递多个参数,譬如: 登录(username,password),我们需要在参数处使用@Param()为参数起名
public User findByNameAndEmail(@Param("name")String username,@Param("email") String email);
6. 添加时如何返回递增的主键值
<!--添加用户
useGeneratedKeys:设置使用生成的主键=true
keyProperty: 赋值给哪个属性
-->
<insert id="addUser" parameterType="com.zpb.entity.User"
useGeneratedKeys="true" keyProperty="userId">
insert into tbl_user values(null,#{username},#{email})
</insert>
7. 解决列名和属性名不一致
第一种: 为查询的列起别名,而别名和属性名一致。
<!--根据id查询学生信息-->
<select id="findOne" resultType="com.zpb.entity.Student">
select stu_id id,stu_name name,stu_age age from tb_stu where stu_id=#{id}
</select>
第二种: 使用resultMap完成列和属性之间的映射关系。
<resultMap id="resultMap" type="com.zpb.entity.Student">
<!--主键的映射关系 column:列名 property:属性名-->
<id column="stu_id" property="id"/>
<!--普通列的映射关系-->
<result column="stu_name" property="name"/>
<result column="stu_age" property="age"/>
</resultMap>
<!--resultType和ResultMap二者只能用一个-->
<select id="findOne" resultMap="resultMap">
select * from tb_stu where stu_id=#{id}
</select>
8. 动态sql
为什么要使用动态sql
传统jdbc⽅法中,在写组合的多表复杂sql语句时,需要去拼接sql语句,稍不注意少写⼀个空格或“”,就会导致报错。
这个Mybatis动态sql的功能,就拥有有效的解决了这个问题,Mybatis动态sql语⾔可以被⽤在任意的sql语句映射中。
mybatis中动态sql标签有哪些?
8.1 if标签--单条件判断
//如果name和password都为null则查询所有
public List<People> findByContains(@Param("name")String name, @Param("password") String password);
<select id="findByContains" resultType="com.zpb.entity.People">
select * from t_people where 1=1
<if test="name!=null and name!=''">
and name=#{name}
</if>
<if test="password!=null and password!=''">
and password=#{password}
</if>
</select>
8.2 choose标签 多条件分支判断
<select id="findByCondition" resultMap="com.zpb.entity.People">
select * from t_people where 1=1
<choose>
<when test="name!=null and name!=''">
and t_name=#{name}
</when>
<when test="age!=null and age!=''">
and t_age=#{age}
</when>
<otherwise>
and t_address="深圳"
</otherwise>
</choose>
</select>
8.3 where标签
我们观察到上面的sql都加了 where 1=1 ,如果不使用where 1=1 那么你的动态sql可能会出错。 我们能不能不加where 1=1呢! 可以 那么我们就可以使用where标签,作用:可以自动为你添加where关键字,并且可以帮你去除第一个and |or
<select id="findByCondition" resultMap="com.zpb.entity.People">
select * from t_people
<where>
<choose>
<when test="name!=null and name!=''">
and t_name=#{name}
</when>
<when test="age!=null and age!=''">
and t_age=#{age}
</when>
<otherwise>
and t_address="深圳"
</otherwise>
</choose>
</where>
</select>
8.4 set标签
这个配合if标签一起用,一般用在修改语句。如果传递的参数值为null,那么应该不修改该列的值。
<!--set:可以帮我们生成关键字 set 并且可以去除最后一个逗号-->
<update id="update">
update account
<set>
<if test="name!=null and name!=''">
name=#{name},
</if>
<if test="money!=null">
money=#{money},
</if>
<if test="isdeleted!=null">
isdeleted=#{isdeleted},
</if>
<if test="created!=null">
created=#{created},
</if>
<if test="updated!=null">
updated=#{updated},
</if>
</set>
where id=#{id}
</update>
8.5 foreach标签
查询:
<!-- select * from account where id in(2,3,5,7,0)
如果你使用的为数组array 如果你使用的为集合 那么就用list
collection:类型
item:数组中每个元素赋值的变量名
open: 以谁开始
close:以谁结束
separator:分割符
-->
<select id="findByIds" resultType="com.zpb.entity.Account">
select * from account where id in
<foreach collection="array" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
删除:
<delete id="batchDelete">
<foreach collection="array" item="id" open="delete from account where id in(" close=")" separator=",">
#{id}
</foreach>
</delete>
添加:
<insert id="saveBatch">
insert into account(name,isdeleted) values
<foreach collection="list" item="acc" separator=",">
(#{acc.name},#{acc.isdeleted})
</foreach>
</insert>
8.6 sql片段
在执行查询语句时不建议大家使用select *, 建议大家把查询的列写出。
//定义sql片段里面包含查询的列名
<sql id="baseColumn">
id , name , mony , isdeleted , created , updated
</sql>
<select id="findBycondition" resultType="com.zpb.entity.Account">
select
<include refid="baseColumn"/>
from account
<where>
<if test="name!=null and name!=''">
and name=#{name}
</if>
<if test="money!=null">
and money=#{money}
</if>
</where>
</select>
8.7 mybatis映射文件处理特殊字符
<!--
第一种:转义标签 <
第二种: <![CDATA[sql]]>
-->
<select id="findByMaxMin" resultType="com.zpb.entity.Account">
<![CDATA[select * from account where id >#{min} and id <#{max}]]>
</select>
8.8 mybatis完成模糊查询
(1)使用concat函数
//select * from 表名 where 列名 like '%a%'
//使用字符串concat函数完成拼接
<select id="findByLike" resultType="com.zpb.entity.Account">
select * from account where name like concat('%',#{name},'%')
</select>
(2)使用${},${}实际上是字符串拼接,它不能防止sql注入, 而#{}它是预编译,它可以防止sql注入问题,#{}实际使用的PreparedStatement.
<select id="findByLike" resultType="com.zpb.entity.Account">
select * from account where name like '%${name}%'
</select>
8.9 联表查询
多对一:根据学生id查询学生信息并携带班级信息
实体类:
如何把连表查询体现在实体类上:创建班级实体类并在学生实体类中用班级类定义属性
package com.zpb.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Clazz {
private Integer cid;
private String cname;
}
package com.zpb.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private int id;
private String name;
private int age;
private String sex;
private Integer classId;
private Clazz clazz;//学生所属的班级
}
xml:
<resultMap id="baseMap" type="com.zpb.entity.Student">
<id column="stu_id" property="id"/>
<result column="stu_name" property="name"/>
<result column="stu_age" property="age"/>
<result column="sex" property="sex"/>
<result column="class_id" property="classId"/>
<!--association: 表示一的一方
property: 它表示属性名
javaType: 该属性名对应的数据类型
-->
<association property="clazz" javaType="com.zpb.entity.Clazz">
<id column="cid" property="cid"/>
<result column="cname" property="cname"/>
</association>
</resultMap>
<select id="findStudentById" resultMap="baseMap">
select * from tb_stu s join tb_class c on s.class_id=c.cid where stu_id=#{id}
</select>
9. 分页插件PageHelper
分页的sql语句:
page: 当前页码
pageSize: 每页显示的条数。
select * from 表名 [where 条件] limit (page-1)*pageSize, pageSize;
如何使用:
(1)引入依赖pagehelper
<!--引入pageHelper-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.11</version>
</dependency>
(2)在mybatis配置文件中设置pagehelper拦截器,注意标签的位置,要在environment标签前,在configuration标签的先后顺序错误了会报红
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
(3)使用pageHelper
//设置分页属性pageNum:显示第几页 PageSize:每页显示的条数
PageHelper.startPage(3,4);
List<User> list = userDao.findAll();
//把查询的结果封装到PageInfo类中。
PageInfo<User> pageInfo=new PageInfo<User>(list);
System.out.println("总条数:"+pageInfo.getTotal());
System.out.println("总页数:"+pageInfo.getPages());
System.out.println("当前页码对应的数据:"+pageInfo.getList());
10. 逆向工程:mybatis的代码生成器--generator
mybatis官方提供了mapper自动生成工具mybatis-generator-core来针对单表,生成PO类,以及Mapper接口和mapper.xml映射文件。针对单表,可以不需要再手动编写xml配置文件和mapper接口文件了,非常方便。美中不足的是它不支持生成关联查询。一般做关联查询,就自己单独写SQL就好了。
generator网址:MyBatis Generator Core – Introduction to MyBatis Generator/
如何使用:
(1)引入mybatis-generator的依赖jar包。
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.4.0</version>
</dependency>
(2)generator的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--找到你的mysql驱动jar的位置-->
<classPathEntry location="D:\repMaven\mysql\mysql-connector-java\8.0.20\mysql-connector-java-8.0.20.jar" />
<context id="DB2Tables" targetRuntime="MyBatis3">
<!--去除自动生成注释-->
<commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--数据源的配置信息-->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai"
userId="root"
password="root">
</jdbcConnection>
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!--java实体类的配置-->
<javaModelGenerator targetPackage="com.aaa.entity" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!--映射文件的配置-->
<sqlMapGenerator targetPackage="mapper" targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!--dao数据访问层的配置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.aaa.dao" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!--数据库表和实体的映射关系
schema:数据库名称
tableName: 表名
domainObjectName:实体类名
enableUpdateByExample:是否生成复杂的修改操作
-->
<table schema="mybatis" tableName="tb_user" domainObjectName="User"
enableUpdateByExample="false" enableSelectByExample="false" enableDeleteByExample="false" enableCountByExample="false">
</table>
<table schema="mybatis" tableName="tb_stu" domainObjectName="Student"
enableUpdateByExample="false" enableSelectByExample="false" enableDeleteByExample="false" enableCountByExample="false">
</table>
</context>
</generatorConfiguration>
(3)运行你的配置文件
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
11. mybatis的缓存
(1)缓存是存放在内存中的临时数据。使用缓存的好处:减少与数据库的交互次数,提高执行效率。
(2)什么样的数据适合放入缓存?
经常变更的数据、数据的正确与否会对最终结果影响很大的数据不适合放入缓存,不经常改变的数据、数据的正确与否对最终结果影响很小的数据适合放入缓存。
(3)mybatis支持的缓存
a. 一级缓存----基于SqlSession级别的缓存。默认一级缓存是开启的,不能关闭。
b. 二级缓存--基于SqlSessionFactory级别的缓存,它可以做到多个SqlSession共享数据。默认它是关闭。需要手动开启。
(4)二级缓存
a. 开启二级缓存
<settings>
<!--开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
b. 在映射文件中使用二级缓存
<!--使用二级缓存 这里面的所有查询都使用了二级缓存-->
<cache/>
禁止指定方法使用二级缓存,设置useCache为false。
<! --通过id查询用户-->
<select id="findUserById" parameterType="int" resultType="user" useCache="false">
SELECT * FROM USER WHERE id = #{id}
</select>
c. 实体一定要实现序列化接口
public class Users implements Serializable{
private Integer id;
private String username;
private String password;
}