MyBatis学习

### Mybatis

环境:

​ jdk1.8

​ Mysql5.7

​ maven:3.6.1

​ idea

SSM框架:配置文件

#### 1,简介

1,1 什么是Mybatis

​ MyBatis 是一款优秀的**持久层**框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

(本是apache的一个开源项目iBatis,2013年迁移到github)

​ 如何获得Mybatis

​ Maven库:

```xml
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
```

 

​ GitHub:https://github.com/mybatis/mybatis-3

​ 中文文档:https://mybatis.org/mybatis-3/zh/index.html

#### 1,持久层

数据持久化

​ 持久化就是将程序在持久状态和瞬时状态转化的过程

​ 内存:断电即失

​ 数据库(jdbc),io文件持久化。

#### 2,新建项目

​ 1,新建一个普通maven项目

​ 2,删除src目录(将当前项目作为父工程)

​ 3,导入Maven依赖

```xml
<!--导入依赖-->
<dependencies>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--mybatis-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
```

#### 3,新建模块

编写mybatis的核心配置文件

```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>
```

 

编写mybatis工具类

#### 4,编写代码

##### 实体类

```java
public class User {
private int id;
private String name;
private String pwd;

public User() {
}

public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPwd() {
return pwd;
}

public void setPwd(String pwd) {
this.pwd = pwd;
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}

```

##### Dao/Mapper接口

```java
public interface UserDao {
List<User> getUserList();
}
```

##### 接口实现类由原来的UserDaoImpl转变为一个Mapper配置文件

```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">

<!--namespace:绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.xiao.dao.UserDao">
<!--查询 id对应-->
<select id="getUserList" resultType="com.xiao.pojo.User">
select * from mybatis.user
</select>
</mapper>
```

#### 5,测试

注意点:

```java
org.apache.ibatis.binding.BindingException: Type interface com.xiao.dao.UserDao is not known to the MapperRegistry.
```

MapperRegistry:核心配置文件中配置Mapper

```xml
<mappers>
<mapper resource="com/xiao/dao/UserMapper.xml"/>
</mappers>
```

 

```java
Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration
```

 

#### 6,CRUD

##### 1,namespace

​ namespace中的包名要和Dao/Mapper的包名一样

##### 2,select

​ 选择,查询语句

​ id:就是对应的namespace中的方法名

​ resultType:Sql语句执行的返回值

​ parameter:参数类型

​ 编写接口

```xml
User selectUser(int id);
```

​ 编写对应的Mapper中的Sql语句

```xml
<select id="selectUser" parameterType="int" resultType="com.xiao.pojo.User">
select * from mybatis.user where id = #{id}
</select>
```

​ 测试

```
@Test
public void queryTest(){
SqlSession sqlSession=MybatisUtils.getSqlSession();
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
User user = userMapper.selectUser(2);
System.out.println(user);

sqlSession.close();
}
```

##### 3,Insert

```xml
<insert id="addUser" parameterType="com.xiao.pojo.User">
insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd});
</insert>
```

##### 4, update

```xml
<update id="updateUser" parameterType="com.xiao.pojo.User">
update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id}
</update>
```

##### 5, delete

```xml
<delete id="deleteUser" parameterType="int">
delete from mybatis.user where id = #{id}
</delete>
```

注意点:增删改需要提交事务。

​ 多个参数可以用Map

#### 7,常见错误

标签要匹配正确

resource绑定mapper,需要使用路径。( / )

NullPointException,没有注册到资源。变量

输出的xml文件中存在中文乱码的问题。右下角查看编码

maven资源导出问题,pom文件加上:

```xml
<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>
```

#### 8,模糊查询

1,java代码执行的时候,传递通配符%

```java
List<User> userList=userMapper.getUserLikeName("%王%");
```

2,在sql拼接中使用通配符

```xml
<select id="getUserLikeName" resultType="com.xiao.pojo.User">
select * from mybatis.user where name like "%"#{name}"%"
</select>
```

#### 9,配置

##### 1,核心配置文件

mybatis-config.xml

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

- configuration(配置)
- [properties(属性)](https://mybatis.org/mybatis-3/zh/configuration.html#properties)
- [settings(设置)](https://mybatis.org/mybatis-3/zh/configuration.html#settings)
- [typeAliases(类型别名)](https://mybatis.org/mybatis-3/zh/configuration.html#typeAliases)
- [typeHandlers(类型处理器)](https://mybatis.org/mybatis-3/zh/configuration.html#typeHandlers)
- [objectFactory(对象工厂)](https://mybatis.org/mybatis-3/zh/configuration.html#objectFactory)
- [plugins(插件)](https://mybatis.org/mybatis-3/zh/configuration.html#plugins)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- [databaseIdProvider(数据库厂商标识)](https://mybatis.org/mybatis-3/zh/configuration.html#databaseIdProvider)
- [mappers(映射器)](https://mybatis.org/mybatis-3/zh/configuration.html#mappers)

##### 2,环境配置

Mybatis可以配置适应多种环境

注意:尽管可以配置多个环境,但是每个SqlSessionFactory只能用一种

Mybatis默认的事务管理是JDBC,默认开启连接池POOLED

##### 3,属性

编写个配置文件

```properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username=XIAO
password=XIAO3363138
```

核心配置文件中映入

```xml
<properties resource="db.properties">
<property name="username" value="XIAO"/>
<property name="password" value="XIAO"/>
</properties>
```

**可以直接引入外部配置文件**

**可以在其中增加一些属性**

**如果两个文件有相同字段,优先使用外部配置文件**

##### 4, 类别名

1. 类别名是为java类型设置的一个短的名称。

2. 存在的意义仅在于用来减少类完全限定名的冗余

```xml
<typeAliases>
<typeAlias type="com.xiao.pojo.User" alias="user"/>
</typeAliases>
```

3. 也可以指定一个包名,Mybatis会在包名下面搜索需要的java Bean,比如

扫描实体类的包,他的默认别名就为这个类的类名,首字母小写

```xml
<typeAliases>
<package name="com.xiao.pojo" />
</typeAliases>
```

在实体类比较少的时候,使用第一种方式。

如果实体类比较多,建议使用第二种

第一种可以DIY别名,第二种则不行,如果非要改,需要在实体类上加注解

```java
@Alias("hello")
public class User {}
```


##### 5,映射器

MapperRegistry:注册绑定Mapper文件

方式一:

```xml
<mappers>
<mapper resource="Mapper.xml"/>
</mappers>
```

方式二:

```xml
<mappers>
<mapper class="com.xiao.dao.UserMapper"/>
</mappers>
```

注意点:

​ 接口和他的Mapper配置文件必须同名

​ 接口和他的Mapper配置文件必须在同一个包下

方式三:

```xml
<mappers>
<package name="com.xiao.dao"/>
</mappers>
```

注意点:

​ 接口和他的Mapper配置文件必须同名

​ 接口和他的Mapper配置文件必须在同一个包下

#### 10,作用域

生命周期,作用域,是至关重要的,因为错误的使用会导致非常严重的并发问题

**SqlSessionFactoryBuilder**:

一旦创建了SQLSessionFactory,就不再需要它了

局部变量

**SQLSessionFactory**:

​ 可以想象为数据库连接池

​ SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,**没有任何理由丢弃它或重新创建另一个实例**

​ 因此SQLSessionFactory的最佳作用域是应用作用域

​ 最简单的使用就是使用单例模式

**SQLSession:**

​ 连接到连接池的一个请求

​ 关闭

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

​ 用完后需要赶紧关闭,否则资源被占用

​ SQLSession里每获得的一个Mapper,就相当于一个具体的业务

#### 11,解决属性名和字段不一样的问题

ResultMap(结果集)

```xml
<resultMap id="UserMapper" type="user">
<result column="pwd" property="password"/>
</resultMap>
```

#### 12,日志

1. 日志工厂

如果一个数据库操作,出现了问题,我们需要排错,日志就很重要

loglmpl:

SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING

在mybatis核心配置文件中配置

```xml
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
```

##### log4j

使用前先导入包

```xml
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
```

在使用Log4j的类中,导入包import org.apache.log4j.Logger;

日志对象,参数为当前类class

```java
static Logger logger = Logger.getLogger(UserMapperTest.class);
```

日志级别

```java
logger.info("info;");
logger.debug("debug;");
logger.error("error;");
```


#### 13,分页

目的:减少数据量处理

使用limit分页

```xml
<select id="getUser" parameterType="map" resultMap="UserMapper">
select * from mybatis.user limit #{starIndex},#{pageSize}
</select>
```

接口

```java
List<User> getUser(Map<String,Integer> map);
```

#### 14,注解开发

在接口上实现

```java
@Select("select * from user where name = #{name}")
User getUserByName(String name);
```

需要在核心配合文件中绑定接口

```xml
<mapper class="com.xiao.dao.UserMapper"/>
```

1. 注解CRUD

```java
@Select("select * from user where id = #{id}")
User getUserById(int id);
@Insert("insert into user(id,name,pwd) values (#{id},#{name},#{pwd})")
int addUser(User user);
@Delete("delete from user where id = #{id}")
int deleteUser(int id);
@Update("update user set name=#{name},pwd=#{pwd} where id =#{id}")
int updateUser(@Param("id") int id,@Param("name") String name,@Param("pwd") String pwd);
```

注意:

```java
public static SqlSession SqlSessionGet() {
return sqlSessionFactory.openSession(true);
}
```

openSession直接设置为true可以自动提交事务

**关于@Param()**

基本类型和String类型需要加上

引用类型不需要加

如果只有一个基本类型的话,可以忽略,但建议加上

我们在SQL中引用的就是@Param中的属性名

#### 15,多对一查询

```java
Student getStudentByID(int id);
```

方式一:

```xml
<select id="getStudentByID" resultMap="st">
select s.id sid,s.name sname,t.id tname
from student s,teacher t
where s.id = t.id;
</select>
<resultMap id="st" type="student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher" >
<result property="name" column="tname"/>
</association>
</resultMap>
```

方式二:

```xml
<select id="getStudentByID" resultMap="ST">
select * from mybatis.student where id = #{id}
</select>
<resultMap id="ST" type="student">
<association property="teacher" column="tid" javaType="Teacher" select="getTeacherByID"/>
</resultMap>
<select id="getTeacherByID" resultType="teacher">
select * from mybatis.teacher where id = #{id}
</select>
```

 

#### 16,一对多查询

POJO

```java
public class Teacher {
private int id;
private String name;
List<Student> students;
}
```

Mapper

```java
Teacher getTeacher(@Param("tid") int tid);
Teacher getTeacher2(@Param("tid") int tid);
```

方式一

```xml
<select id="getTeacher" resultMap="ts">
select t.id tid,t.name tname,s.name sname,s.id sid
from student s,teacher t
where t.id=s.tid and t.id = #{tid};
</select>
<resultMap id="ts" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
```

方式二

```xml
<select id="getTeacher2" resultMap="TS">
select * from mybatis.teacher where id = #{tid};
</select>
<resultMap id="TS" type="Teacher">
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudent" column="id"/>
</resultMap>
<select id="getStudent" resultType="Student">
select * from mybatis.student where tid = #{tid}
</select>
```

#### 17,动态SQL

根据不同条件生成不同SQL语句

```java
List<Blog> queryBlog(Map map);
List<Blog> queryBlog2(Map map);
int updateBlog(Map map);
```

**if**

```xml
<select id="queryBlog" parameterType="map" resultType="blog">
select * from mybatis.blog where 1=1
<if test="title != null">
and title = #{title}
</if>
</select>
```

**choose,when**,**otherwise**

```xml
<select id="queryBlog2" parameterType="map" resultType="blog">
select * from mybatis.blog where 1=1
<choose>
<when test="title!=null">
and title = #{title}
</when>
<when test="author!=null">
and author = #{author}
</when>
<otherwise>
and id=#{id}
</otherwise>
</choose>
</select>
```

**trim,where,set**

```xml
<update id="updateBlog" parameterType="map">
update mybatis.blog
<set>
<if test="title!=null">title=#{title},</if>
<if test="author!=null">author=#{author},</if>
</set>
where id = #{id}
</update>
```

测试时title或author附一个值,不然会报错

**sql标签**

```xml
<sql id="if-title">
<if test="title != null">
and title = #{title}
</if>
</sql>
<select id="queryBlog" parameterType="map" resultType="blog">
select * from mybatis.blog where 1=1
<include refid="if-title"></include>
</select>
```

#### 18,缓存

1. 什么是缓存【Cache】?

存在内存中的临时数据

将用户经常查询到的数据存放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中从而提高效率,解决了高并发系统性能问题

2. 为什么使用缓存

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

3. 什么样数据适合使用缓存

经常查询且不改变的数据

**MyBatis缓存**

MyBatis系统中定义了两级缓存:一级缓存和二级缓存

​ 默认情况下,只有一级缓存开启。(SQLSession级别的缓存,也称为本地缓存)

​ 二级缓存需要手动开启和配置,他是基于namespace级别的缓存

​ 为了提高扩展性,MyBatis定义了缓存接口Cache,我们可以通过实现Cache来定义二级缓存接口

缓存Cache配置:

1.核心文件中的属性配置:开启全局缓存

```xml
<setting name="cacheEnabled" value="true"/>
```

2.在Mapper.xml文件中添加<cache/>标签

注意:如果readOnly为false,此时要结果集对象是可序列化的。实现Serialization接口

```xml
<cache readOnly="false"/>
```

 

posted @ 2020-09-17 22:55  秋天开始后  阅读(111)  评论(0)    收藏  举报