目录
1.什么是ORM思想?
O:object,对应jvm中的对象
R:relational,关系型数据库
M:mapping,映射
就是java对象与数据库之间的映射关系,叫做ORM思想。
2.第一个MyBatis程序
1.创建maven项目
2.添加mybatis依赖和mysql驱动依赖,如下:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
3.在类路径下创建mybatis-config.xml,文件内容如下:
<?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"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
4.在类的根路径下编写XxxMapper.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="org.mybatis.example.BlogMapper">
<insert id="insertCar">
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values (null,'1003','丰田霸道', 30.0 , '2000-10-11','燃油车');
</insert>
</mapper>
5.在mybatis-config.xml中的mapper标签中指定XxxMapper.xml的路径,如:
<mappers>
<mapper resource="CarMapper.xml"/>
</mappers>
6.编写java程序,其中sqlSessions是执行sql语句的一个会话对象。
sqlSession怎么获取:通过sqlSessionFactory
sqlSessionFactory怎么获取:通过sqlSessionFactoryBuilder的build方法
7.示例代码如下:
public class MyBatisIntroductionTest {
public static void main(String[] args) throws IOException {
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 默认从类的根路径查找资源
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
// 参数是CarMapper.xml中insert标签的id
int count = sqlSession.insert("insertCar");
System.out.println("插入的记录条数" + count);
// 手动提交
sqlSession.commit();
}
}
3.MyBatis的事务管理机制
有两个,在transactionManager标签中指定:
<transactionManager type="JDBC"/>
type可选JDBC和MANAGED
JDBC:mybatis框架自己管理事务,自己采用原生的JDBC代码去管理事务
MANAGED:mybatis不再负责事务的管理,交给其他容器管理如spring。
4.MyBatis中的日志框架
在mybatis-config.xml文件中配置如下即可:
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
默认已经实现了STDOUT_LOGGING(标准日志)
如果没有在这里配置,可以添加别的日志框架依赖,mybatis会自动查找,如添加logback依赖,然后在类路径下添加logback.xml即可,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 配置文件修改时重新加载,默认true -->
<configuration debug="false">
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder" charset="UTF-8">
<!-- 输出日志记录格式 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- mybatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<!-- 日志输出级别,LOGBACK日志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR-->
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
5.MyBatis插入对象
需要注意,声明的对象属性和数据库里的列名是一一对应的,支持驼峰对应。mapper的xml文件中#{}表示属性占位符,对应java中的属性名。
@Data
@AllArgsConstructor
public class Car {
private Long id;
private String carNum;
private String brand;
private Double guidePrice;
private String produceTime;
private String carType;
}
<insert id="insertCar">
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values (#{id}, #{carNum}, #{brand}, #{guidePrice}, #{produceTime}, #{carType});
</insert>
@Test
public void testCarByPojo(){
SqlSession sqlSession = SqlSessionUtil.openSession();
Car car = new Car(null, "3333", "比亚迪秦", 30.00, "2020-11-11", "新能源");
int count = sqlSession.insert("insertCar", car);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
6.MyBatis查询操作
注意mapper中需要指定返回的结果对象,如:
<select id="selectById" resultType="com.duolaimi.mybatis.pojo.Car">
select * from t_car where id = #{id}
</select>
查单个或者多个的返回结果类型都是pojo的全限定类名。
7.命名空间的作用
为了防止id的冲突,因为可能存在相同的方法。
8.数据源的分类
mybatis配置了三种数据源分类:
UNPOOLED:不使用数据库连接池技术,每次请求都是创建新的Connection对象
POOLED:使用mybatis自己实现的数据库连接池
JNDI:集成其他第三方的数据库连接池
9.properties标签的配置和使用
新建jdbc.properties放在类路径下,内容如下:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/duolaimi
jdbc.username=root
jdbc.password=root
在mybatis-config.xml中添加如下配置:
<properties resource="jdbc.properties"/>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
表示读取类路径下的jdbc.properties文件,并且使用${}匹配properties中的key。
10.namespace和增删改查标签中的id限定
namespace必须是类的全限定类名,标签中的id必须是方法名,这样底层的javassist工具才能定位到mapper中的sql语句。
11.使用面向接口的方式进行CRUD
只需声明好接口,然后在接口中编写方法名,与mapper.xml中的命名空间与id对应上即可,如下:
public interface CarMapper {
int insert(Car car);
}
<?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="com.duolaimi.mybatis.mapper.CarMapper">
<insert id="insert">
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values (#{id}, #{carNum}, #{brand}, #{guidePrice}, #{produceTime}, #{carType});
</insert>
</mapper>
@Test
public void testInsert(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car = new Car(null, "4444", "比亚迪秦", 30.00, "2020-11-11", "新能源");
int insert = mapper.insert(car);
System.out.println(insert);
sqlSession.commit();
}
12.#{}与${}的区别
#{}:底层使用PreparedStatement。特点:先进行SQL语句的编译,然后给SQL语句的占位符?传值,可以避免SQL注入的风险。
${}:底层使用Statement。特点:先进行SQL语句的拼接,然后再对SQL语句进行编译,存在SQL注入的风险。
13.什么时候可以使用${}?
执行的sql语句中,变量是表示sql的关键字的时候,只能用${},如传参表示desc或者acs的查询。
传参用于拼接表名的时候,也必须使用${}。
14.如何使用别名
可以在mabatis-config.xml核心配置文件中添加:
<typeAliases>
<typeAlias type="com.duolaimi.mybatis.pojo.Car" alias="car"/>
</typeAliases>
在mapper文件中指定resultType时,就可以通过alias来获取类的全限定名称。(别名不区分大小写,且alias属性可以省略,如果省略就是类的简名)
或者使用pakage标签,会将指定包下的类全部自动起别名:
<typeAliases>
<package name="com.duolaimi.mybatis.pojo"/>
</typeAliases>
15.实际扫描mapper.xml文件的方式
一般情况下,我们会使用指定包的方式来确定扫描的mapper.xml的文件路径,如在mybatis-config.xml中配置:
<mappers>
<package name="com.duolaimi.mybatis.mapper"/>
</mappers>
但是前提是编译后的xml文件必须和接口文件放在一起,目录结构如下:
16.使用自动生成的主键值
需要在insert标签中加入两个属性,示例如下:
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values (#{id}, #{carNum}, #{brand}, #{guidePrice}, #{produceTime}, #{carType});
</insert>
主要属性是:
useGeneratedKeys="true":开启并使用自动生成主键
keyProperty="id":生成的主键值会赋值到的java对象的属性名
17.MyBatis传参时传多个参数的解决方法
如果不通过@Param注解,则底层默认会将第一个参数设置为arg0或者param1,第二个参数设置为arg1或者param2,以此类推。
可以通过@Param("")指定map中的key,在mapper.xml中写指定的key即可。
18.@MapKey注解的使用
放在方法上,比如@MapKey("id")说明返回时,将原来map中的id字段放到新的map中作为key。
19.结果映射
可以使用resultMap标签来定义结果映射,映射java中属性与数据库中列的关系。
<resultMap id="carResultMap" type="car">
<id property="id" column="id"/>
<result property="carNum" column="car_num"/>
<result property="carType" column="car_type"/>
</resultMap>
<select id="selectById" resultMap="carResultMap">
select * from t_car where id = #{id}
</select>
注意,select标签中需要加上resultMap属性,且该属性值为上面resultMap标签中的id。
id属性最好加上,会提高查询效率。
当属性名与字段名一致时,property标签可以省略。
20.驼峰命名自动映射
可以在mabatis-config.xml核心配置文件中添加如下配置:
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
即可开启驼峰自动映射,默认是false。
21.动态SQL
1.if标签
if标签中必须有test属性,结果为true或者false,如果使用了@Param注解,test中出现的参数可以为@Param中的值,如果是传的POJO参数,则可以传POJO中的属性名。
2.where标签
主要是嵌套if标签,如果其中的if标签都不成立则不会加where语句,并且多个if成立时,会自动去除语句前面的and或or(注意,不能去除写在语句后面的and或or)
3.trim标签
trim标签常用属性:
prefix:加前缀
suffix:加后缀
prefixOverrides:删除前缀
suffixOverrides:删除后缀
4.set标签
主要是嵌套if标签,多条件时会自动去除if标签后面的逗号。
5.choose标签
choose标签里面一般会配合when标签和otherwise标签一起使用,类似if_else的语法,当前面的成立后,下面就不会执行,也就说choose标签中只能有一个成立,例如:
6.foreach标签
可以执行批量操作如in语句。
foreach标签中常用的属性:
collection:传@Param中的值,否则是Array或者arg0
item:每次循环的对象,对应标签体中的对象
seperator:使用的分隔符,通常都是“,”
open:循环开始符号
close:循环结束符号
如果执行的是批量插入,则不需要open和close属性,示例如下:
#{}中需要写item中指定的对象的属性
7.sql标签与include标签
他们主要是为了代码复用,sql标签声明好后,include标签使用refid将sql的id引用过来,达到代码复用。
22.多对一映射方式
1.级联属性的方式
使用resultMap属性,在多的一方的类加入一的一方的类作为属性,然后resultMap中以“.”的方式赋值属性,如下图所示:
2.使用association标签
在resulltMap中使用association标签,指定属性和java对应的类型即可,示例如下:
3.分步查询
先查学生表数据,返回列中包含cid(班级id),让后指定resultMap,再指定association标签,指定班级的查询语句和传入的参数(column)。
具体如下:
优点:
1.复用性增强,可以重复利用
2.可以充分利用他们的延迟加载/懒加载机制
23.什么是延迟加载
延迟加载的核心原理是:用的时候再执行查询语句,不用的时候不查询。
如何开启:在association标签中,添加fetchType属性,设置成lazy。(默认情况未开启)
如果在association标签中定义的延迟加载是局部开启的,如果想要全局开启,则需要在mybatis-conf.xml核心配置文件中定义,如下所示:
如果全局已定义延迟加载,则局部的延迟加载可以去除。
实际开发中都是需要延迟加载的,建议开启全局的延迟加载。如果不希望语句使用延迟加载,则配置fetchType为eager,则全部加载。
24.一对多映射方式
1.使用collection标签
使用resultMap标签,其中使用collection标签,加上ofType属性,用于指定集合中元素的类型。
2.分步查询
类似上面的分步查询,只是里面是集合时用的标签是collect标签,示例如下:
25.MyBatis中的缓存机制
将select语句的查询结果放到缓存(内存)中,下一次还是这条select语句的时候,直接从缓存中取,不再查数据库。一方面是减少了IO,另一方面不再执行繁琐的查找算法,效率大大提升。
1.一级缓存
默认开启,不需要做任何配置,范围是一个sqlSession,也就是说只要是同一个和SqlSession对象执行同一条SQL语句,就会走缓存。
2.一级缓存的失效
在第一次DQL和第二次DQL之间,如果做了以下两种的任意一种,都会清空一级缓存:
1.执行了sqlSession的clearCache()方法,这是手动清空一级缓存
2.执行了DML(增删改)语句,不管是操作哪张表,都会清空一级缓存
3.二级缓存
二级缓存的范围是SqlSessionFactory
使用二级缓存需要具备以下几个条件:
1.<setting name="cacheEnabled" value="true">全局性地开启或关闭所有映射器配置文件中已配置的任何缓存,默认是true,无需配置。
2.在需要使用二级缓存的SqlMapper.xml文件中添加配置:<cache/>
3.使用二级缓存的实体类对象必须是可序列化的,也就是必修实现Serializable接口
4.SqlSession对象关闭或提交后,一级缓存中的数据才会被写入到二级缓存当中,此时二级缓存才可用。
4.二级缓存的失效
在两次查询之间进行了增删改造作,就会失效。
26.逆向工程
1.添加逆向工程插件
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.1</version>
<configuration>
<!--允许覆盖-->
<overwrite>true</overwrite>
</configuration>
<!--插件的依赖-->
<dependencies>
<!--mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
2.在根路径下新建generatorConfig.xml文件,内容如下:
<?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>
<!--
targetRuntime有两个值:
MyBatis3Simple:生成的是基础版,只有基本的增删改查。
MyBatis3:生成的是增强版,除了基本的增删改查之外还有复杂的增删改查。
-->
<context id="DB2Tables" targetRuntime="MyBatis3">
<!--防止生成重复代码-->
<plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>
<commentGenerator>
<!--是否去掉生成日期-->
<property name="suppressDate" value="true"/>
<!--是否去除注释-->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--连接数据库信息-->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/duolaimi"
userId="root"
password="root">
</jdbcConnection>
<!-- 生成pojo包名和位置 -->
<javaModelGenerator targetPackage="com.duolaimi.mybatis.pojo" targetProject="src/main/java">
<!--是否开启子包-->
<property name="enableSubPackages" value="true"/>
<!--是否去除字段名的前后空白-->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成SQL映射文件的包名和位置 -->
<sqlMapGenerator targetPackage="com.duolaimi.mybatis.mapper" targetProject="src/main/resources">
<!--是否开启子包-->
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 生成Mapper接口的包名和位置 -->
<javaClientGenerator
type="xmlMapper"
targetPackage="com.duolaimi.mybatis.mapper"
targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 表名和对应的实体类名-->
<table tableName="t_stu" domainObjectName="Stu"/>
</context>
</generatorConfiguration>
3.在该文件中修改数据库连接信息,生成的包信息,需要生成的表信息等
4.双击运行插件即可
如果使用增强版,会生成一个XxxExample类,主要是做条件查询对象的,具体用法如下:
StuExample mapper1 = sqlSession.getMapper(StuExample.class);
mapper1.createCriteria().andAgeBetween(...);
27.分页插件
分页插件的使用:
1.引入依赖:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.3</version>
</dependency>
2.在mybatis-config.xml核心配置文件中添加拦截器:
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>
3.只要在需要分页查询的前面加入以下代码,即可自动分页:
PageHelper.startPage(1,2);
如果想要查看分页数据的详细信息,可以使用PageInfo对象。
List<Car> list = new ArrayList<>();
PageInfo<Car> carPageInfo = new PageInfo<>(list, 3);
28.集成日志框架(logback)
1.在pom文件中添加logback的依赖坐标:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
2.在类路径下创建logback.xml文件,指定日志输出格式,文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 配置文件修改时重新加载,默认true -->
<configuration debug="false">
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder" charset="UTF-8">
<!-- 输出日志记录格式 -->
<pattern>[%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- mybatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<!-- 日志输出级别,LOGBACK日志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR-->
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</configuration>