1.简介
1.1 什么是Mybatis
- MyBatis 是一款优秀的持久层框架
- 它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
1.2 持久层
数据持久化
- 持久化就是将程序的数据在持久状态和顺势状态转化的过程
- 内存:断电即失
- 数据库(jdbc),io文件持久化。
为什么需要持久化?
有一些对象,不能让他丢掉。
- 内存太贵
1.3 持久层
Dao层,Service层,Controller层
- 完成持久化工作的代码块
- 层界限十分明显
1.4 为什么需要Mybatis?
- 帮助程序员将数据存入到数据库中
- 方便
- 传统的JDBC代码复杂。简化。框架
- 不用Mybatis也可以。更容易上手。技术没有高低之分
- 优点:
- 简单易学
- 灵活
- sql和代码的分离,提高了可维护性。
- 提供映射标签,支持对象与数据库的orm字段关系映射
- 提供对象关系映射标签,支持对象关系组建维护
- 提供xml标签,支持编写动态sql。
最重要的一点:使用的人多!
2.第一个Mybatis程序
思路:搭建环境–>导入Mybatis–>编写代码–>测试!
2.1 搭建环境
<?xml version="1.0" encoding="UTF-8"?>
<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.imnu</groupId>
<artifactId>Mybatis_Demo01</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
<!-- 在build中配置resources,来防止我们资源导出失败的问题-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
2.2 创建一个模块
-
编写mybatis的核心配置文件
-
<?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核心配置文件--> <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?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> </configuration>
-
编写mybatis工具类
-
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; //SqlSessionFactory-->SqlSession public class MybatisUtil { private static SqlSessionFactory sqlSessionFactory; static { try { //使用Mybatis获取sqlSessionFactory对象 String resource = "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(); } }
2.3 编写代码
-
实体类
-
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; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", pwd='" + pwd + '\'' + '}'; } }
-
Dao接口
-
public interface UserDao { List<User> getUserList(); }
-
接口实现类由原来的UserDaoImpl转化为一个Mapper配置文件
-
<?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="dao.UserDao"> <!-- select查询语句--> <select id="getUserList" resultType="pojo.User"> select * from mybatis.mybatis </select> </mapper>
2.4 测试
注意点:
org.apache.ibatis.binding.BindingException: Type interface dao.UserDao is not known to the MapperRegistry.
MapperRegistry是什么?
核心配置文件中注册mappers
-
junit测试
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import pojo.User;
import util.MybatisUtil;
import java.util.List;
public class UserDaoTest {
@Test
public void test(){
//第一步:获得sqlSession对象
SqlSession sqlSession = MybatisUtil.getSqlSession();
//方式一:执行sql
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.getUserList();
//方式二:
List<User> userList = sqlSession.selectList("dao.UserDao.getUserList");
for (User user:userList) {
System.out.println(user);
}
//关闭SqlSession
sqlSession.close();
}
}
-
官方建议
-
import org.apache.ibatis.session.SqlSession; import org.junit.Test; import pojo.User; import util.MybatisUtil; import java.util.List; public class UserDaoTest { @Test public void test(){ //第一步:获得sqlSession对象 SqlSession sqlSession = MybatisUtil.getSqlSession(); try { //方式一:执行sql UserDao userDao = sqlSession.getMapper(UserDao.class); List<User> userList = userDao.getUserList(); //方式二: // List<User> userList = sqlSession.selectList("dao.UserDao.getUserList"); for (User user:userList) { System.out.println(user); } }catch (Exception e){ e.printStackTrace(); }finally { //关闭SqlSession sqlSession.close(); } } }
可能会遇见的问题:
- 配置文件没有注册
- 绑定接口错误
- 方法名不对
- 返回类型不对
- Maven导出资源问题
3.增删改查(※)
3.1 namespace
namespace中的包名要和Dao接口的包名一致!
3.2 select
选择,查询语句
- id:对应的namespace中的方法名
- resultType:sql语句执行的返回值
- parameterType:返回的参数类型
- 编写接口
//根据ID查询用户
User getUserById(int id);
- 编写对应的mapper中的sql语句
<select id="getUserById" parameterType="int" resultType="pojo.User">
select *
from mybatis.mybatis
where id = #{id}
</select>
- 测试
@Test
public void getUserById() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User userById = mapper.getUserById(1);
System.out.println(userById);
sqlSession.close();
}
3.3 Insert
//插入用户
int addUser(User user);
<!-- 对象中的属性可以直接取出来-->
<insert id="addUser" parameterType="pojo.User">
insert into mybatis.mybatis
values (#{id}, #{name}, #{pwd});
</insert>
//增删改需要提交事务
@Test
public void addUser() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res = mapper.addUser(new User(5, "eee", "eee"));
if (res > 0) {
System.out.println("插入成功!");
}
//提交事务
sqlSession.commit();
sqlSession.close();
}
3.4 Updata
//修改用户
int updataUser(User user);
<update id="updataUser" parameterType="pojo.User">
update mybatis.mybatis
set name = #{name},
pwd=#{pwd}
where id = #{id};
</update>
3.5 Delete
//删除一个用户
int deleteUser(int id);
<delete id="deleteUser" parameterType="int">
delete
from mybatis.mybatis
where id = #{id};
</delete>
@Test
public void deleteUser() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteUser(1);
sqlSession.commit();
sqlSession.close();
}
注意点:增删改需要提交事务
3.6 Map
我们的实体类,或者数据库中的表,字段或者参数过多,应当考虑使用Map
int addUser2(Map<String,Object>map);
<insert id="addUser2" parameterType="map">
insert into mybatis.mybatis(id,name,pwd)
values (#{userid}, #{userName}, #{passWord});
</insert>
//增删改需要提交事务
@Test
public void addUser2() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> map = new HashMap<>();
map.put("userid",6);
map.put("userName","mmm");
map.put("passWord","mmm");
mapper.addUser2(map);
//提交事务
sqlSession.close();
}
Map传递参数,直接在sql中取出key即可!
对象传递参数,直接在sql中取对象的属性即可!
只有一个基本类型参数的情况下,直接在sql中取到。
多个参数用Map,或者注解。
3.7 模糊查询
-
Java代码执行的时候,传递通配符%xxx%
List<User> bb= mapper.getUSerLike("%bb%");
-
在sql拼接中使用通配符!
select * from mybatis.mybatis where name like "%"#{value}"%"
4.配置解析
4.1 核心配置文件
-
mybatis-config.xml
-
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
-
configuration(配置)
-
properties(属性)
-
settings(设置)
-
typeAliases(类型别名)
-
typeHandlers(类型处理器)
-
objectFactory(对象工厂)
-
plugins(插件)
-
environments(环境配置)
-
environment(环境变量)
-
transactionManager(事务管理器)
-
dataSource(数据源)
-
databaseIdProvider(数据库厂商标识)
-
mappers(映射器)
-
4.2 环境配置(environments)
MyBatis可以配置成适应多种环境
不过要记住:尽管能配置多个环境,但每一个SqlSessionFactory实例只能选择一种环境。
-
学会使用配置多套运行环境
-
Mybatis默认的事务管理器就是JDBC,连接池:POOLED
4.3 属性(properties)
我们可以通过properties属性来实现引用配置文件
这些属性可以在外部进行配置,并可以进行动态替换。既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。【db.properties】
- 在xml中,所有的标签都可以规定其顺序
编写一个配置文件
dirver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username=root
password=root
在核心配置文件中映入
<!--引入外部配置文件-->
<properties resource="dbcpconfig.properties">
<property name="username" value="root"/>
<property name="password" value="1111"/>
</properties>
- 可以直接引入外部文件
- 可以在其中增加一些属性配置
- 如果两个文件有同一个字段,优先使用外部配置文件的!
4.4 类型别名(typeAliases)
- 类型别名是为Java类型设置的短的名字。
- 存在的意义仅在于用来减少类完全限定名的冗余。
<!--给实体类起别名-->
<typeAliases>
<typeAlias type="pojo.User" alias="User"/>
</typeAliases>
也可以指定一个包名,MyBatis会在包名下搜索需要的JavaBean,比如:
扫描实体类的包,他的默认别名就为这个类的类名,首字母小写!
<!--给实体类起别名-->
<typeAliases>
<package name="pojo"/>
</typeAliases>
-
在实体类比较少的情况下,使用第一种方式。
-
如果实体类十分多,建议使用第二种。
-
第一种可以DIY别名,第二种则不行,如果在实体类上增加注解
@Alias("user") public class User{}
4.5 设置
这是MyBatis中极为重要的调整设置,它们会改变MyBatis的运行时行为。
4.6 其他配置
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- mybatis-generator-core
- mybatis-plus
- 通用mapper
4.7 映射器(mappers)
MapperRegistry:注册绑定我们的Mapper文件
方式一:
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
方式二:使用class文件绑定注册
<mappers>
<mapper class="dao.UserMapper"/>
</mappers>
注意点:
- 接口和他的Mapper配置文件必须同名
- 接口和他的Mapper配置文件必须在同一个包下
方式三:使用扫描包进行注入绑定
<mappers>
<package name="dao"/>
</mappers>
注意点:
- 接口和他的Mapper配置文件必须同名
- 接口和他的Mapper配置文件必须在同一个包下
4.8 生命周期和作用域
作用域和生命周期类是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoryBuilder:
- 一旦创建了SqlSessionFactory,就不再需要它了
- 局部变量
SqlSessionFactory:
-
可以想象为:数据库连接池
-
SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
-
因此SqlSessionFactory的最佳作用域就是应用作用域。
-
最简单的就是使用单例模式或者静态单例模式。
SqlSession:
- 可以想象为:连接到连接池的一个请求!
- SqlSession的实例不是线程安全的,因此是不能被共享的,所以他的最佳作用域是请求或方法作用域。
- 用完之后需要赶紧关闭,否则资源被占用!
这里面的每一个Mapper,就代表一个具体的业务!