mybatis学习笔记
Mybatis
环境:
- JDk1.8
- Mysql 5.7
- maven 3.6.1
- IDEA
回顾 :
- JDBC
- MYsql
- Java基础
- Junit 测试
框架是有配置文件的, 最好的学习方式是看官方文档 ;
1 简介
1.1 什么是Mybatis
- Mybatis是一款优秀的持久层框架
如何获得Mybatis
-
Maven仓库
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency>
-
github : https://github.com/mybatis/mybatis-3
1.2 持久化
数据持久化 :
- 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
- 内存中的数据 : 断电即数据丢失
- 数据库(Jdbc) / io文件持久化
为什么需要持久化?
- 有一些对象不能丢失
- 内存太贵
1.3 持久层
之前接触过 Dao层 / Service层 / Controller层 ...
什么是持久层?
- 完成持久化工作的代码块
- 层是界限十分明显的
1.4 为什么需要Mybatis?
- 帮助程序员将数据存入数据库
- 方便
- 传统的JDBC代码太复杂了 , 为了简化代码的框架
- 自动化
最重要的一点 :
- 使用的人多
2 第一个mybatis程序
思路 : 搭建环境-> 导入Mybatis-> 编写代码-> 测试
2.1 创建表
CREATE DATABASE IF NOT EXISTS `mybatis`;
USE `mybatis`;
CREATE TABLE IF NOT EXISTS `user`(
`id` INT(20) NOT NULL PRIMARY KEY,
`name` VARCHAR(30) DEFAULT NULL,
`pwd` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB CHARSET=utf8;
INSERT INTO `user`(`id`, `name`, `pwd`)VALUES
(1, 'karl', '123456'),
(2, 'xiao', '123434'),
(3, 'gels', '123321');
2.2新建一个maven项目
mybatis-01/ pom.xml
<!--父工程-->
<dependencies>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
2.3 创建模块
创建mabatis配置文件
src/ main/ recource/ 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>
<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/mybatis?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
创建工具类
package com.karl.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
* @author admin
* @version 1.0.0
* @ClassName MybatisUtils.java
* @Description 工具类 sqlSessionFactory -> sqlSession
* @createTime 2021年03月19日 13:18:00
*/
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory = null;
static{//获取sqlSessionFactory对象
String resource = "mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//sqlSession完全包含了面向数据库执行SQL命令需要的所有方法
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
2.3 编写代码
-
实体类
package com.karl.pojo; /** * @author admin * @version 1.0.0 * @ClassName User.java * @Description 实体类 * @createTime 2021年03月21日 13:21:00 */ 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 + '\'' + '}'; } }
-
mapper接口
package com.karl.mapper; import com.karl.pojo.User; import java.util.List; /** * @author admin * @version 1.0.0 * @ClassName UserMapper.java * @Description Dao接口 * @createTime 2021年03月21日 13:27:00 */ public interface UserMapper { List<User> getUserList(); }
-
接口实现类由原来的DaoImpl转变为一个Maper配置文件
<?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="com.karl.mapper.UserMapper"> <select id="getUserList" resultType="com.karl.pojo.User"> select * from user </select> </mapper>
2.4 测试
注意 : BindingException: Type interface com.karl.dao.UserDao is not known to the MapperRegistry.
-
junit测试
官方推荐的格式
确保 SqlSession 关闭的标准模式:
try (SqlSession session = sqlSessionFactory.openSession()) { // 你的应用逻辑代码 }
package com.karl.mapper; import com.karl.pojo.User; import com.karl.utils.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; /** * @author admin * @version 1.0.0 * @ClassName UserMapperTest.java * @Description 测试sql * @createTime 2021年03月21日 13:59:00 */ public class UserMapperTest { @Test public void test(){ try (SqlSession sqlSession = MybatisUtils.getSqlSession()) { //执行 UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> userList = mapper.getUserList(); for (User user : userList) { System.out.println(user); } } } }
-
在mybatis-config中配置mapper
<!--每一个Mapper.xml都需要在Mybatis-config核心配置文件中注册--> <mappers> <mapper resource="com/karl/mapper/UserMapper.xml"/> </mappers>
-
maven中配置文件存放的问题
<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>
3 CRUD
namespace中的包名要和mapper接口的包名一致
- id : 是namespace中的方法名
- resultType : Sql语句的返回值
- parameterType : 参数类型
1 select
选择 , 查询语句
接口 UserMapper.java
//按id查找用户
User getUserByID(int id);
UserMapper.xml
<select id="getUserByID" parameterType="int" resultType="com.karl.pojo.User">
select * from mybatis.user where id = #{id}
</select>
@Test
public void getUserByID(){
try (SqlSession sqlSession = MybatisUtils.getSqlSession()){
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User userByID = mapper.getUserByID(1);
System.out.println(userByID);
}
}
2 insert(增删改需要提交事务)
插入语句
接口 UserMapper.java
//添加一个用户
int addUser(User user);
UserMapper.xml
<!--对象中的属性可以直接拿出来-->
<insert id="addUser" parameterType="com.karl.pojo.User">
insert into mybatis.user (id, name, pwd) values (#{id}, #{name}, #{pwd});
</insert>
@Test
public void addUser(){
try (SqlSession sqlSession = MybatisUtils.getSqlSession()){
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User(4, "kkk", "123432");
mapper.addUser(user);
sqlSession.commit();
}
}
3 update
//修改用户
int updateUser(User user);
<update id="updateUser" parameterType="com.karl.pojo.User">
update mybatis.user
set name = #{name},
pwd = #{pwd}
where id = #{id};
</update>
@Test
public void updateUser(){
try(SqlSession sqlSession = MybatisUtils.getSqlSession()){
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User(5, "lll", "111222");
int result = mapper.updateUser(user);
sqlSession.commit();
if (result > 0){
System.out.println("修改成功");
}
}
}
4 delete
//删除一个用户
int deleteUser(int id);
<delete id="deleteUser" parameterType="int">
delete from mybatis.user where id = #{id}
</delete>
@Test
public void deleteUser(){
try(SqlSession sqlSession = MybatisUtils.getSqlSession()){
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int result = mapper.deleteUser(5);
sqlSession.commit();
if (result > 0){
System.out.println("删除成功");
}
}
}
5 常见错误
6 万能的map
在参数或字段过多的时候 , 可以考虑使用map
弹幕提示调试很麻烦
//使用Map添加一个用户
int addUser2(Map<String, Object> map);
<!--使用map传递参数-->
<insert id="addUser2" parameterType="map">
insert into mybatis.user(id, name, pwd)
values (#{userID}, #{userName}, #{password});
</insert>
@Test
public void addUser2(){
try (SqlSession sqlSession = MybatisUtils.getSqlSession()){
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Object> stringObjectHashMap = new HashMap<>();
stringObjectHashMap.put("userID",10);
stringObjectHashMap.put("userName","uuu");
stringObjectHashMap.put("password","iiiii");
mapper.addUser2(stringObjectHashMap);
sqlSession.commit();
}
}
8 模糊查询怎么写
-
java执行代码时传递通配符
List<User> userList = mapper.getUserLike("%k%");
-
在sql拼接中使用通配符(报错)
select * from mybatis.user where name like "%" #{value} "%";
4 配置解析
配置顺序
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- environment(环境变量)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
1 核心配置文件(mybatis-config)
mybatis-config.xml
名字可以随便取 , 但官方推荐用这个名字
The content of element type "configuration" must match "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)".
文件中的配置需要按照此顺序
2 environments(环境配置
MyBatis 可以配置成适应多种环境,不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
使用default="development"
切换多套环境
mybatis 默认的事务管理器是JDBC , 连接为POOLED(池)
3 属性(properties)
可以使用peoperties属性引用配置文件
编写一个配置文件db.properties
drier=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=true
username=root
password=123456
在核心配置文件(mybatis-config.xml)中引入
<properties resource="mybatis/db.properties"></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>
-
可以引入外部文件
-
也可以在
<properties resource="mybatis/db.properties"> <property name="" value=""/> </properties>
中添加属性
-
两个文件有同一个字段 , 优先使用外部属性
4 类型别名(typeAliases)
-
可为 Java 类型设置一个缩写名字 , 意在降低冗余的全限定类名书写。
<!--别名--> <typeAliases> <typeAlias type="com.karl.pojo.User" alias="User"/> </typeAliases>
-
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean , 别名默认为这个类名但首字母为小写
<typeAliases> <package name="com.karl.pojo"/> </typeAliases>
可以使用注解自定义名字
@Alias("author") public class Author { ... }
5 设置(settings)
![image-20210402112137183](https://i.loli.net/2021/04/02/FPLw9R6YGVHOco1.png)
6 其他配置
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- mybatis-generator-core
- mybatis-puls
- 通用mapper
7 映射器 mapper
-
方式一
<mappers> <mapper resource="mybatis/mapper/UserMapper.xml"/> </mappers>
-
方式二 : 使用class的文件绑定
<mappers> <mapper class="com.karl.mapper.UserMapper"/> </mappers>
-
方式三 : 使用包扫描绑定
<mappers> <package name="mybatis.mapper"/> </mappers>
-
方式二和方式三必须注意 :
- 接口和它的Mapper配置文件必须同名 ;
- 接口和它的Mapper配置文件必须在同一个包下 ;
- 解决maven的资源导出问题 ;
8 生命周期和作用域
作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoryBuilder :
- 它是用来创建SqlSessionFactory 的,
- 一旦创建了 SqlSessionFactory,就不再需要它了。
SqlSessionFactory :
- 可以理解为数据库连接池
- 一旦被创建就应该在应用的运行期间一直存在
- 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次
- 因此 SqlSessionFactory 的最佳作用域是应用作用域
- 最简单的就是使用单例模式或者静态单例模式
SqlSession :
- 连接到连接池的一个请求
- 用完就要关闭
- 每个线程都应该有它自己的 SqlSession 实例
- SqlSession 的实例不是线程安全的,因此是不能被共享的
- 所以它的最佳的作用域是请求或方法作用域
5 解决属性名和字段名不一致的问题
当类中的属性名和数据库中的方法不一致时 :
例如 :
类中的属性名为 password
而数据库中的字段是 pwd
时出现的不能读取到的问题 ;
1. 可以"起别名"
select id,name,pwd as password form mybatis.user where id = #{id};
2 . 可以使用 ResultMap
结果集映射
<resultMap id="UserMap" type="User">
<!--column数据库中的字段 , property实体类中的属性-->
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserByID" resultMap="UserMap">
select * from mybatis.user where id = #{id}
</select>
6 日志
6.1 日志工厂
在debug时 , 日志是很好的排错手段
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
掌握 :
- STDOUT_LOGGING
- LOG4J
STDOUT_LOGGING
<settings>
<setting name="logImpl" value="STDOUT_LOGGING">
</settings>
- 设置名和值不能错
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 log4j.appender.console.layout.ConversionPattern=[%c]-%m%n #文件输出的相关设置 log4j.appender.file = org.apache.log4j.RollingFileAppender log4j.appender.file.File=./log/kuang.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
-
将
LOG4J
设置为日志实现<settings> <setting name="logImpl" value="LOG4J"/> </settings>
简单使用
-
导入包
import org.apache. log4j.Logger;
-
创建对象
static Logger logger = Logger.getLogger(UserDaoTest.class);
-
在需要的地方调用方法
logger.info;