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"/>
```
浙公网安备 33010602011771号