Mybatis
Mybatis简介
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。可以参考官网学习Mybatis
Mybatis简单使用
创建maven项目,与之前的第一个servlet程序的流程一样
配置环境,在父项目的pom.xml导入依赖,pom.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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.chen</groupId>
<artifactId>Mybatis-test</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<!--子项目-->
<modules>
<module>Mybatis-01</module>
</modules>
<!--导入依赖-->
<dependencies>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<!--junit单-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<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>
</project>在resource目录下编写Mybatis的核心配置文件
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
<!--configuration核心配置文件-->
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--这里用&代替&-->
<property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</dataSource>
</environment>
</environments>
<!--每一个xml都需要在核心配置里加载映射-->
<mappers>
<mapper resource="com/chen/dao/getUserList.xml"/>
</mappers>
</configuration>编写Mybatis工具类
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易。
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//sqlSessionFactory -->sqlSession
public class Mybatisutils {
private static SqlSessionFactory sqlSessionFactory;
static{
try {
//使用Mybatis第一步:获取sqlSessionFactory对象
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
// SqlSession 提供了在数据库执行 SQL 命令所需的所有方法
//你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}定义接口类
1
2
3
4
5public interface UserMapper {
List<user> getUserList();
user getUserById(int id);
}编写xml文件(同目录下好管理),写好xml之后需要到核心配置处加载映射
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--一个namespace绑定一个接口-->
<mapper namespace="com.chen.dao.UserMapper">
<!--id表示接口中的方法名,parameterType为接收的参数类型,resultType为返回的类型-->
<!--对应接口中的getUserList方法-->
<select id="getUserList" resultType="com.chen.pojo.user">
select * from mybatis
</select>
<!--对应接口中的getUserById方法-->
<select id="getUserById" parameterType="int" resultType="com.chen.pojo.user">
select *from mybatis where id= #{id}
<!--#{id}是接收getUserById定义的参数-->
</select>
</mapper>调用
使用工具类中的getSqlSession方法获取sqlSession对象
通过sqlSession对象的getMapper方法获得接口的实现
- 然后通过实现的接口对象来调用方法
- 关闭sqlSession对象
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
30public class UserDaoTest {
public void test(){
//1
SqlSession sqlSession = Mybatisutils.getSqlSession();
//2
UserMapper mapper = sqlSession.getMapper(UserMapper.class); //class对象获得接口信息
//3
List<user> userlist = mapper.getUserList();
for(user u:userlist){
System.out.println(u.getId()+"---"+u.getName()+"---"+u.getPwd());
}
//4
sqlSession.close();
}
public void getUserById(){
//1
SqlSession sqlSession = Mybatisutils.getSqlSession();
//2
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//3
user u = mapper.getUserById(1);
System.out.println(u.getId()+"---"+u.getName()+"---"+u.getPwd());
//4
sqlSession.close();
}
}
增删改查
增删改都是需要提交事务的
接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14package com.chen.dao;
import com.chen.pojo.user;
import java.util.List;
public interface UserMapper {
List<user> getUserList();
user getUserById(int id);
int addUser(user u);
int updateUser(user u);
int deleteUser(int id);
}绑定的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<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.chen.dao.UserMapper">
<select id="getUserList" resultType="com.chen.pojo.user">
select * from mybatis
</select>
<select id="getUserById" parameterType="int" resultType="com.chen.pojo.user">
select *from mybatis where id= #{id}
</select>
<insert id="addUser" parameterType="com.chen.pojo.user">
insert into mybatis(id,name,pwd) values(#{id},#{name},#{pwd})
</insert>
<update id="updateUser" parameterType="com.chen.pojo.user">
update mybatis set name=#{name},pwd=#{pwd} where id=#{id}
</update>
<delete id="deleteUser" parameterType="int">
delete from mybatis where id = #{id}
</delete>
</mapper>测试类
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62package com.chen.dao;
import com.chen.pojo.user;
import com.chen.utils.Mybatisutils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserDaoTest {
public void test(){
//获得sqlSession对象
SqlSession sqlSession = Mybatisutils.getSqlSession();
//执行sql语句
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<user> userlist = mapper.getUserList();
for(user u:userlist){
System.out.println(u.getId()+"---"+u.getName()+"---"+u.getPwd());
}
//关闭sqlSession
sqlSession.close();
}
public void getUserById(){
SqlSession sqlSession = Mybatisutils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
user u = mapper.getUserById(1);
System.out.println(u);
sqlSession.close();
}
// 增删改的的操作都是需要commit提交事务的,不然实现不了
public void Adduser(){
SqlSession sqlSession = Mybatisutils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.addUser(new user(4, "liuliu", "4"));
sqlSession.commit();
sqlSession.close();
}
public void UpdateUser(){
SqlSession sqlSession = Mybatisutils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser(new user(4,"六六","5"));
sqlSession.commit();
sqlSession.close();
}
public void DelteUser(){
SqlSession sqlSession = Mybatisutils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteUser(4);
sqlSession.commit();
sqlSession.close();
}
}
Mybatis的配置详情
Mybatis配置文件就是resources文件下的mybatis-config.xml。虽然可以改名,官方推荐使用这个名字
需要注意的是,这些配置是按顺序的,比如环境配置是不能放在属性配置前面的,不然会报错
环境配置(envirnments)
MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类推
1 | <environments default="development"> |
环境的选择,如果没有环境参数就会选择默认环境,即上述default的环境id
1
2SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);事务管理器的配置
如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置。
1
<transactionManager type="JDBC"/>
数据源的配置
1
<dataSource type="POOLED">
属性(properties)
属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。
固定的属性可以直接放在外部的配置文件,比如在resources资源目录下创建一个config-properties文件,&可以不用转译
1
2
3
4driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC
username = root
password = password然后在配置文件中调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<configuration>
<properties resource="config.properties"/>
<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="com/chen/dao/UserMapper.xml"/>
</mappers>
</configuration>也可以动态的调用,比如
1
2driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC在配置文件中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<configuration>
<properties resource="config.properties">
<property name="username" value="root"/>
<property name="password" value="password"/>
</properties>
<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="com/chen/dao/UserMapper.xml"/>
</mappers>
</configuration>注意的是,外部的优先级较高,在配置文件中properties属性与外部文件的属性冲突时是使用外部文件的属性
类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
类
1
2
3<typeAliases>
<typeAlias alias="user" type="com.chen.pojo.user"/>
</typeAliases>包
1
2
3<typeAliases>
<package name="com.chen.pojo"/>
</typeAliases>指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean。在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。比如在Mybatis会自动扫描路径上的包,在没有注解的情况下,里面的user类的别名就会定义为user
通过注解来起别名
1
2
3
4
public class user {
}
设置(Settings)
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。了解几个就行
设置名 | 描述 | 有效值 | 默认值 | |||||
---|---|---|---|---|---|---|---|---|
cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true\ | false | true | ||||
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 |
true\ | false | false | ||||
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J\ | LOG4J\ | LOG4J2JDK_LOGGING\ | COMMONS_LOGGING\ |
STDOUT_LOGGING \ |
NO_LOGGING | 未设置 |
映射器(mappers)
既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:///
形式的 URL),或类名和包名等。
使用相对于类路径的资源引用,推荐使用这种
1
2
3
4
5<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>使用完全限定资源定位符(URL),不推荐
1
2
3
4
5<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>使用映射器接口实现类的完全限定类名
- 接口与Mapper配置文件同名
- 接口和它的Mapper配置文件同包
1
2
3
4
5<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>将包内的映射器接口实现全部注册为映射器
- 接口与Mapper配置文件同名
- 接口和它的Mapper配置文件同包,也可以将它的Mapper配置文件放在resources下创建相同路径的文件夹
1
2
3<mappers>
<package name="org.mybatis.builder"/>
</mappers>
作用域(Scope)和生命周期
理解我们之前讨论过的不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoryBuilder
- 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。
- 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
SqlSessionFactory
- SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
- 因此 SqlSessionFactory 的最佳作用域是应用作用域。
SqlSession
- 每个线程都应该有它自己的 SqlSession 实例。
- SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
- 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行,也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中。
- 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。
属性名与字段不一致
在有些操作里,会因为pojo包里的属性名与数据库的字段名不一样而会达不到应有效果,比如有时候会查不到不同属性名的值,所以就要注意属性名要与字段一致,要是不一样还有一些其他的解决方法。
起别名
为你不同的属性名取一个与字段一样的别名,这样就能实现属性名与字段一致,比如属性名为password,字段名为pwd,则为password起一个pwd的别名
1 | <typeAliases> |
ResultMap
resultMap为结果集映射,将你的字段名映射为属性名,便能使属性名与字段一致
1 | <resultMap id="result" type="user"> |
日志
Mybatis 通过使用内置的日志工厂提供日志功能。因为Mybatis的设置日志是为设置的,所以需要设置才能看得到
STDOUT_LOGGING
1 | <settings> |
Log4j
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIXSyslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
导入依赖
1
2
3
4
5
6<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>在resouces目录下创建log4j.properties配置文件,并设置配置,网上很多可以去复制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#将等级为DEBUG的日志信息输出到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
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关配置
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/Mybatis.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.sql.PreparedStatement=DEBUG设置日志实现
1
2
3<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
注解
对于像 BlogMapper 这样的映射器类来说,还有另一种方法来完成语句映射。 它们映射的语句可以不用 XML 来配置,而可以使用 Java 注解来配置。
注解
1
2
3
4public interface UserMapper {
List<user> getUserList();
}去核心配置文件处绑定接口
1
2
3<mappers>
<mapper class="com.chen.dao.UserMapper"/>
</mappers>
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。