Mybatis笔记
1、第一个Mybatis程序
- 首先删除src,然后更改maven的路径设置。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5aJr7GP1-1602485368187)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20200908195726334.png)]
1、注意:配置pom.xml中的resources,防止资源导出失败的问题
<!-- 配置resources,防止资源导出失败的问题-->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
- 引入资源
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
</dependencies>
2、创建resources连接
1、mysql驱动问题
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
2、url问题
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8"/>
?serverTimezone=UTC解决SQL时区问题
3、resources绑定mapper
mybatis-config.xml中mapper属性resources要填路径
3、乱码问题
- 输出的xml文件中有乱码问题,删除输出文件中乱码,重新调试
4、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核心配置文件-->
<configuration>
<typeAliases>
<package name="com.cat.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.cat.mapper.UserMapper"/>
</mappers>
</configuration>
2、万能的Map
如果我们的实体类,或者数据库中的表,字段或者参数比较多,我们应当考虑使用Map!(虽然不规范,但是很实用,以后可能会帮到大忙)
1、Map
// 万能的Map
int addUser(Map<String,Object>map);
<insert id="addUser" parameterType="map">
-- 传递Map的键
insert into mybatis.user(id,name,pwd) values(#{userid},#{userName},#{password});
</insert>
// 万能的Map
@Test
public void addUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String,Object> map=new HashMap<String, Object>();
map.put("userid",3);
map.put("userName",4);
map.put("password",5);
}
2、模糊查询
- Java代码执行的时候,传递通配符%李%
//模糊查询
List<User> getLikeUser(String value);
<select id="getLikeUser" resultType="com.wildcata.pojo.User">
select * from user where name like "%"#{value}"%"
</select>
@Test
public void getLikeUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> likeUser = mapper.getLikeUser("李");
for (User user:likeUser){
System.out.println(user);
}
}
3、配置解析
1、映射器
- 接口和他的Mapper配置文件必须同名
- 接口和他的Mapper配置文件必须放在同一文件夹下
2、生命周期和作用域
注意:错误的使用会导致非常严重的并发问题
1、SQLSessionFactory
- 一旦创建就没有理由丢弃或重新创建另一个实例
3、免提交修改
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession(true);
}
4、日志
在mybatis-config.xml中配置日志
SQL错误会有提示信息
1、标准日志
<settings>
<!-- 标准的日志配置输出-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
2、LOG4J
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
- log4j.properties配置
# 将等级为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
#%c: 输出日志信息所属的类目,通常就是所在类的全名
#%m: 输出代码中指定的消息,产生的日志具体信息
#%n: 输出一个回车换行符,Windows平台为"/r/n",Unix平台为"/n"输出日志信息换行
log4j.appender.console.layout.ConversionPattern=[%C]-%m%n
# 文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File = ./log/test.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
5、Lombok
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass
- 常用的注解
@Data:无参构造函数,get,set,toString,...
@AllArgsConstructor
@NoArgsConstructor
- 首先要在plugs中安装Lombok
- 导入Lombok包
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
</dependencies>
6、多对一(一对多)
- 多个学生对一个老师
- 对学生而言,多个学生关联一个老师
- 对老师而言,是一种集合
1、测试环境
- 导入lombok
- 新建实体类Teacher,Student
- 建立Mapper接口
- 建立Mapper.xml文件
- 在核心配置文件绑定所有的Mapper接口文件
- 测试查询是否能成功
2、查询所有学生以及对应老师
使用resultMap
- association 对象(老师是一个对象)
- collection 集合(学生是一个集合)
1、方法一(子查询)
<select id="getAllStudent" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="com.cat.pojo.Student">
<association property="teacher" column="tid" javaType="com.cat.pojo.Teacher" select="getTeacherById"/>
</resultMap>
<select id="getTeacherById" resultType="com.cat.pojo.Teacher">
select * from teacher where id=#{id}
</select>
@Test
public void getAllStudent(){
SqlSession sqlSession = MybatisUilts.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> allStudent = mapper.getAllStudent();
for(Student student:allStudent)
System.out.println(student);
sqlSession.close();
}
2、方法二(联表查询)
<select id="getAllStudent2" resultMap="StudentTeacher2">
select s.id sid,s.name sname,t.name tname from student s,teacher t where s.tid=t.id
</select>
<resultMap id="StudentTeacher2" type="com.cat.pojo.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" column="tid" javaType="com.cat.pojo.Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
@Test
public void getAllStudent2(){
SqlSession sqlSession = MybatisUilts.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> allStudent = mapper.getAllStudent2();
for(Student student:allStudent)
System.out.println(student);
sqlSession.close();
}
7、一对多处理
一个老师多个学生
对老师而言是一对多关系
- 环境搭建
<select id="getAllTeacher" resultMap="TeacherStudent">
select t.id tid,t.name tname,s.id sid,s.name sname,s.tid tid from teacher t,student s where t.id=s.tid
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="studentList" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
<select id="getAllTeacher2" resultMap="TeacherStudent2">
select * from teacher
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<collection property="studentList" column="id" javaType="ArrayList" ofType="Student" select="getStudent"/>
</resultMap>
<select id="getStudent" resultType="Student">
select * from student where tid=#{tid}
</select>
@Test
public void getAllTeacher(){
SqlSession sqlSession = MybatisUilts.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
List<Teacher> allTeacher = mapper.getAllTeacher();
for(Teacher teacher:allTeacher)
System.out.println(teacher);
sqlSession.close();
}
@Test
public void TeacherStudent2(){
SqlSession sqlSession = MybatisUilts.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
List<Teacher> allTeacher2 = mapper.getAllTeacher2();
for (Teacher teacher : allTeacher2) {
System.out.println(teacher);
}
sqlSession.close();
}
小结
-
关联-association【多对一】
-
集合-collection【一对多】
-
javaType & ofType
- javaType 用来指定实体类中属性的类型
- ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束
注意点:
- 保证SQL的通俗易懂(可读性)
- 注意一对多和多对一中的,属性名和字段问题
- 有问题不好排错,可以使用日志
- 慢SQL 1s 1000s(尽量避免慢SQL)
面试高频
- mysql引擎
- innodb底层原理
- 索引
- 索引优化
8、动态SQL
IF
<select id="getBlogByTItleOrAuther" parameterType="map" resultType="Blog">
select * from blog
<where>
<if test="title !=null">
and title=#{title}
</if>
<if test="author !=null">
and author=#{author}
</if>
</where>
</select>
- where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
- set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号
- where,有前缀and | or
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
- prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。
- set有后缀,
<trim prefix="SET" suffixOverrides=",">
...
</trim>
总结
所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码
SQL片段
有时,我们需要将一些功能部分抽取出来,方便复用
1、使用SQL标签抽取公共部分
<sql id="if-title-author">
<if test="title !=null">
and title=#{title}
</if>
<if test="author !=null">
and author=#{author}
</if>
</sql>
2、在需要使用的地方使用include标签引用
<select id="getBlogByTItleOrAuther" parameterType="map" resultType="Blog">
select * from blog
<where>
<include refid="if-title-author"></include>
</where>
</select>
注意事项:
- 最好基于单表来定义SQL片段
- 不要存在where标签
Foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符
<select id="queryForeach" parameterType="map" resultType="Blog">
select * from blog
<where>
<foreach collection="ids" item="id" open="(" close=")" separator="or">
id = #{id}
</foreach>
</where>
</select>
动态SQL就是拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以
建议:
- 先在mysql中写出完整的SQL,再去对应的去修改成我们的动态SQL实现通用即可
9、缓存
减少和数据库的交互次数
经常查询并且不常改变的数据
- 一级缓存和二级缓存
- 默认只有一级缓存开启(SQLSession,本地)
- 二级缓存需要手动开启和配置,基于namespace级别的缓存
- 为了提高拓展性,mybatis定义了缓存接口cache,我们可以通过他来自定义二级缓存