Mybatis

环境要一致
框架:配置文件的,最好

1、简介

1、什么是MyBatis

1、MyBatis是一筐优秀的持久成框架
2、它支持定制化SQL、存储过程以及高级映射
3、MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
4、MyBatis可以使用简单的XML或注解来配置和映射原生类型、接口和java的POJO(Plain Old java Object,普通老式java对象)为数据库中的记录
5、MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis
6、2013年11月迁移达到Github

2、持久化

数据持久化
持久化就是将程序的数据都在持久状态和瞬时状态转化的过程
持久状态:放到数据库,不删除数据库一直存在
瞬时状态:断电就丢失

3、持久层

完成持久化工作对的代码块
层界限十分明显

4、为什么需要MyBatis

1、方便
2、传统的JDBC代码太复杂了。简化 框架 自动化
3、帮助程序员将数据存入数据库

2、使用Mybits查询

例:config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?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>
<!-- default选择默认环境,也就是 environment中的id值 -->
<environments default="guao">
<environment id="guao">
<!-- 事务管理 -->
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<!--
useSSL=true 设置安全连接
&emp; 转义后为 &
useUnicode=true 使用unicode编码
characterEncoding=UTF-8 设置编码格式
-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mygrade?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>

<!-- 引入CRUD的xml -->
<mappers>
<mapper resource="dao/Student.xml"/>
</mappers>
</configuration>

1、方法一

例:Student.xml

1
2
3
4
5
6
7
8
9
<?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="ss">
<!-- resultType的值为返回对的类型 -->
<select id="StuQuery" resultType="vo.Student">
select * from student
</select>
</mapper>

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class text1 {
public static void main(String[] args) throws IOException {
InputStream in = Resources.getResourceAsStream("config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//自动提交
SqlSession session = factory.openSession(true);
List<Student> list = session.selectList("StuQuery");
for (Student student : list) {
System.out.println(student);
}

session.close();

}
}

2、方法二

例:Student.xml

1
2
3
4
5
6
7
8
9
<?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="service.User">
<!-- resultType的值为返回对的类型 -->
<select id="getUserList" resultType="vo.Student">
select * from student
</select>
</mapper>

例:User.java

1
2
3
public interface User {
public List<Student> getUserList();
}

注意!!!!
Student.xml中的namespace=的值为User.java接口的地址
User.java里面的类名必须姚和Student.xml对的id一一对应,否则会找不到

测试:

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) throws IOException {
InputStream in = Resources.getResourceAsStream("config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//自动提交
SqlSession session = factory.openSession(true);
User a = session.getMapper(User.class);
List<Student> list = a.getUserList();
for (Student student : list) {
System.out.println(student);
}
session.close();//关闭
}

3、配置解析

1、核心配置文件

核心配置文件通常命名为:mybatis-config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
conflguration(标签)
properties(属性)
settings(设置)
typeAliases(设置别名)
typeHandles(类型处理器)
objectFactory(对象工厂)
plugins(插件)

environments(环境配置)
environment(环境变量)
transactionManager(事务过滤器)
ddataSource(数据源)
databaseldProvlder(数据库厂商标识)
mappers(映射器)
必须要按照这个顺序来,否则会报错

2、environments(环境配置)

Mybatis 可以配置多种环境
注:虽然可以多种,但是只能实例化一种
Mybatis默认的事务管理器JDBC,连接池:POOLED

3、properties(属性)

基本上用于引入外部配置文件来连接数据源

配置:jdbc.properties

1
2
3
4
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/school
name=root
pass=123456

例:

方法一

1
<properties resource="jdbc.properties" />

方法二

1
2
3
4
<properties resource="jdbc.properties">
<!--也可以在里面配置-->
<property name="username" value="root" />
</properties>

但是优先调用外部引入的配置文件键

引入后:

1
2
3
4
5
6
7
8
9
10
11
12
<properties resource="db.properties" />
<environments default="guao">
<environment id="guao">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${name}" />
<property name="password" value="${pass}" />
</dataSource>
</environment>
</environments>

4、typeAliases(设置别名)

给java类型设置一个短的名字

1
2
3
<typeAliases>
<typeAlias alias="stu" type="vo.Student"/>
</typeAliases>

注意!!!!
若不写alias指定别名,则默认最后面的路径为别名,不区分大小写

例:

1
2
3
4
<typeAliases>
<typeAlias type="vo.Student"/>
</typeAliases>

也可以根据注释来设置别名,在类上添加@Alias(“别名”)

则该别名为student

例:

1
2
@Alias("stu")
public class Student{}

5、生命周期

生命周期

生命周期和作用域,是最关主要的,因为错误的使用辉导致严重的并发问题

SqlSessionFactioryBuilder

​ 一旦创建了SqlSessionFactory,就不需要创建了

​ 局部变量

SqlSessionFactory

​ 数据库连接池

​ 一旦被穿件则运行期一直存在,没办法丢弃或重新创建

​ 因此最佳作用域是应用作用域,最简单对的使用单例模式或者静态单例模式

SqlSession

​ 连接连接池的一个请求

​ SqlSession的实例不是线程安全,因此不能被共享,最佳作用域是请求或方法作用域

​ 用完后关闭,否则浪费资源

里面每一个Mapper就代表一个具体的业务

4、解决属性名与字段名不一致

例 :

  • 数据库字段 sid sname

  • 属性字段 id name

    字段名不一样,数据库则找不到对应的属性,所以会造成数据找出来,但没赋值进去

1、解决方法一

修改sql语句

例:

1
select sid id,sname,name from student

但是我们往往不推荐修改sql语句

2、解决方法二

用xml中的标签

1
2
3
<resultMap type="类型" id="命名">
<result column="数据库字段" property="属性字段"></result>
</resultMap>

并且把sql语句中的resultType改为resultMap值为对应的resultMap的id属性
只需要映射不一样的就行了

例:

1
2
3
4
5
6
7
8
9
10
11
12
<?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="service.User">
<resultMap type="Student" id="UserMap">
<result column="sid" property="id"></result>
</resultMap>
<!-- resultType的值为返回对的类型 -->
<select id="getUserList" resultMap="UserMap">
select * from student
</select
</mapper>

resultMap元素是MyBatis中最强大的元素

ResultMap的设计思路是,对于简单的语句根本不需要配置式的结果映射,而对于复杂一点的语句只需要描述他们的关系即可

5、日志

1、日志工厂

img

  • SLF4J

  • LOG4J 【掌握】

  • LOG4J2

  • JK_LOGGING

  • COMMONS_lOGGING

  • STDOUT_lOGGING 【掌握】

  • NO_LOGGING

    STDOUT_LOGGING标准日志输出

在mybatis_config配置
例:

1
2
3
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

注!!!

1
<setting name="logImpl" value="STDOUT_LOGGING"/>使用这个,必需一模一样,否则报错

2、Log4j

  • Log4j是Apache的一个开源项目,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件

  • 通过定义每一条日志信息的几倍,我们能够更细致的控制生成过程

  • 通过一个配置文件来灵活的进行配置,不需要修改原来的代码

    1. 先导入log4j的包

    2. 在src路径下创建log4j.properties 内容为

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      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=./log/guao.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.PreparedStatement=DEBUG

    3. 在mybatis.xml中配置log4j为日志实现

      1
      2
      3
      <settings>
      <setting name="logImpl" value="STDOUT_LOGGING"/>
      </settings>

6、使用注解开发

我们通常可以把简单的sql语句用注解打在方法上用于简便我们的代码结构,过于复杂的sql语句,我们还是写与xml中

使用方法

  1. 在接口的方法上添加sql语句注解

    • @Insert 添加注解
    • @Select 查询注解
    • @Delete 删除注解
    • @Update 修改注解
    1
    2
    3
    4
    5
    例:
    public interface User {
    @Select("select * from student")
    public List<Student> getUserList();
    }
  2. 在mybatis.xml中添加扫描该接口xml语句

    1
    2
    3
    <mappers>
    <mapper class="service.User"/>
    </mappers>

    其他跟以前的一致

  3. 如果需要根据指定值查询则

    1、sql语句通过#{参数}获取,方法参数必须要跟#{参数}一致

    例:

    1
    2
    @Select("select * from student where sid=#{sid}")
    public List<Student> getUserList(int sid);

    2、通过使用注解@@Param,类似于取别名

    例:

    1
    2
    @Select("select * from student where sid=#{sid}")
    public List<Student> getUserList(@Param("sid") int s);

    3、也可以使用属性类,根据属性类的属性,

    例:

    1
    2
    @Select("select * from student where sid=#{id}")
    public List<Student> getUserList(Student stu);

7、设置自动提交

在需要执行sql语句时候,增加以下这段代码,则会自动提交

1
SqlSession session = factory.openSession(true);

8、复杂的sql语句

复杂的属性,我们需要单独处理

1、多对一

例:根据学生查出班级(根据学生的tid ,查出班级)

方法一:查询时嵌套

例:vo.Student

1
2
3
4
5
6
public class Student {
private int id;
private String sname;
private String gender;
private Clazz clazz;
}

例:vo.Clazz

1
2
3
4
public class Clazz{
private int cid;
private String caption;
}

例:student.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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="service.User">

<resultMap type="vo.Student" id="UserClass">
<result property="id" column="sid"/>
<result property="sname" column="sname"/>
<result property="gender" column="gender"/>
<association property="clazz" javaType="vo.Clazz" >
<result property="cid" column="cid"/>
<result property="caption" column="caption"/>
</association>
</resultMap>

<select id="UserList" resultMap="UserClass">
select * from student,class where student.class_id=class.cid
</select>
</mapper>

注意:

  • column为数据库字段
  • property为属性类字段

例:测试类

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) throws IOException {
InputStream in = Resources.getResourceAsStream("mybatis_config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//自动提交
SqlSession session = factory.openSession(true);
User a = session.getMapper(User.class);
List<Student> list = a.UserList();
for (Student student : list) {
System.out.println(student);
}
session.close();
}

方法二:查询结果嵌套

属性类跟上面一致

**例:student.xml **

1
2
3
4
5
6
7
8
9
10
11
12
<resultMap type="vo.Student" id="UserClass">
<result property="id" column="sid"/>
<result property="sname" column="sname"/>
<result property="gender" column="gender"/>
<association property="clazz" javaType="vo.Clazz" >
<result property="cid" column="cid"/>
<result property="caption" column="caption"/>
</association>
</resultMap>
<select id="UserList" resultMap="UserClass">
select * from student,class where student.class_id=class.cid
</select>

2、一对多

例:一个班级有多个学生

方法一、查询时嵌套

例:clazz.java

1
2
3
4
5
public class clazz{
private int cid;
private String caption;
private List<Student> student;
}

配置clazz.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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="stu">
<resultMap type="vo.Clazz" id="ClassMap">
<id property="cid" column="cid"/>
<result property="caption" column="caption"/>
<!-- 班级类中添加学生类的集合 -->
<collection property="stu" ofType="vo.Student" column="cid" select="clazz" />
</resultMap>
<select id="selectClazzAll2" resultMap="ClassMap">
select * from class
</select>
<select id="clazz" resultType="vo.Stuent">
select * from student where class_id=#{cid}
</select>
</mapper>

方法二:结果嵌套查询

配置clazz.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?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="service.Clazzl">
<resultMap type="vo.Clazz" id="ClassMap">
<id property="cid" column="cid"/>
<result property="caption" column="caption"/>
<!--集合中使用泛值,则使用ofType-->
<collection property="student" ofType="vo.Student" column="cid">
<id property="id" column="sid"/>
<result property="sname" column="sname"/>
<result property="gender" column="gender"/>
</collection>
</resultMap>
<select id="getClazz" resultMap="ClassMap">
select * from Class c left join Student s on c.cid = s.class_id
<!--这sql可以查出空学生的班级-->
<!--
select * from class,student where class.cid=student.class_id
这sql不能查出没有学生的班级
-->
</select>
</mapper>

3、小结

1、关联-association【多对一】

2、集合-collection【一对多】

3、javaType & ofType

​ 1、javaType 用来指定实体类中额属性类型

​ 2、ofType用来指定映射到集合中的pojo类型,泛型中的约定类型

注意:

1、保证sql语句通俗易懂

9、动态sql

1、IF

1
2
3
4
5
6
7
8
xml配置
<select id="getList" resultType="vo.Student">
select * from student where 1=1
<if test="id!=null">
and sid=#{id}
<!--id为Student中的属性-->
</if>
</select>

接口配置

1
2

public List<Student> getList(Student stu);

2、where

如果不用这个表情,那么我们使用动态sql查询的时候,必须要添加where 1=1

当我们加上where,当条件不成立,则会自动去除where,而且where还会判断是否是第一个条件,是则会自动去除and

简便后:

1
2
3
4
5
6
7
8
<select id="getList" resultType="vo.Student">
select * from student
<where>
<if test="id!=null">
and sid=#{id}
</if>
</where>
</select>

3、choose

choose内有俩个子标签when跟otherwise,

when标签,当执行成功一个,则不会再执行下一个

otherrwise标签,当前面的条件都不成立,则运行

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<select id="getList" resultType="vo.Student">
select * from student
<where>
<choose>
<when test="id!=0">
and sid=#{id}
</when>
<when test="sname!=null">
and sname==#{sname}
</when>
<otherwise>
and gender=#{gender}
</otherwise>
</choose>
</where>
</select>

4、set

set通常用于修改,会帮我们去除无关紧要的逗号

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
<update id="setStudent" >
update student
<set>
<if test="sname!=null">
sname=#{sname},
</if>
</set>
<where>
<if test="id!=0">
sid=#{id}
</if>
</where>
</update>

5、sql

提取出来公共的部分

使用include连接起来,可以让大部分的sql重用,不要添加where,尽量有if判断就差不多了

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<sql id="select">
select * from student
</sql>

<select id="getList" resultType="vo.Student">
<include refid="select"></include>
<where>
<choose>
<when test="id!=0">
and sid=#{id}
</when>
<when test="sname!=null">
and sname==#{sname}
</when>
<otherwise>
and gender=#{gender}
</otherwise>
</choose>
</where>
</select>

6、foreach

当我们要根据多个id,姓名查询时,我们会用到foreach

  • collection的值为遍历的集合
  • item的值为遍历集合之后的id
  • open的值为以什么开始
  • close的值为以什么结束
  • separator的值为分隔符

例:

1
2
3
4
5
6
7
8
<select id="studentForeach" resultType="vo.Student" parameterType="map">
select * from student
<where>
<foreach collection="ids" item="id" open="(" close=")" separator="or">
sid=#{id}
</foreach>
</where>
</select>

注意:当使用foreach时,where不会自动2省略and,我暂时也不知道为什么

10、缓存

1、简介

概念:存在内存中的临时数据,将经常查询的数据放在缓存中,用户查询数据这就不用在数据库查询,从缓存中查询,从而提高查询效率,解决高并发系统的性能问题。

优点:减少和数据库的交互次数,减少系统开销,提高系统效率

常用地方:经常查询并不经常改变的数据

2、MyBatis缓存

  • MyBatis包含一个非常强大的查询缓存22特性,他可以非常方便德的定制和配置缓存。缓存可以极大额提升查询效率
  • MyBatis系统默认俩种缓存:一级缓存和二级缓存
    • 默认情况下,只有一级缓存开启(SqlSession级别的缓存,也称为本地缓存)
    • 二级缓存需要手动开启和配置,他基于namespace级别额缓存
    • 为了提高扩展性,MyBatis定义缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

3、一级缓存

sqlSession.clearCache() 手动清理缓存

只能保存一次的查询结果