环境:
-
JDK1.8
-
MySql5.7
-
Maven3.8.1
-
IDEA
回顾:
-
JDBC
-
Mysql
-
Java基础
-
Maven
-
Junit(单元测试模块)
1.简介
1.1 什么是Mybatis?
-
MyBatis 是一款优秀的持久层框架
-
它支持自定义 SQL、存储过程以及高级映射。
-
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
1.2 什么是持久化?
数据持久化
-
持久化就是将程序的数据在持久状态和瞬时状态转化的过程
为什么需要持久化?
-
有一些对象不能丢弃
-
内存太贵了
1.3 持久层
Dao层,Service层,Controller层
-
完成持久化操作的代码块
-
层界限十分明显(?)
1.4 为什么需要MyBatis
-
方便
-
传统的JDBC代码太复杂。简化。框架。自动化
-
帮助程序员将数据存入到数据库中
-
优点:
-
简单易学
-
灵活
-
sql和代码的分离,提高了可维护性
-
提供映射标签,支持对象与数据库的orm字段关系映射
-
提供对象关系映射标签,支持对象关系组建维护
-
提供xml标签,支持边写动态的sql
-
最重要的一点:使用的人多
2. 第一个Mybatis程序
2.1 搭建环境
创建数据库
SHOW TABLES;
CREATE TABLE `user`(
`id` INT(20) NOT NULL,
`name` VARCHAR(30) NOT NULL,
`pwd` VARCHAR(30) NOT NULL,
PRIMARY KEY(id)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user`(`id`,`name`,`pwd`) VALUES
(1,"Test1","123456"),
(2,"Test2","123456"),
(3,"Test3","123456");
创建Maven项目,导入mysql驱动,mybatis,Junit依赖
略
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>
<!--环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://127.0.0.1:3306/Mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8&"/>
<property name="username" value="mouzhai"/>
<property name="password" value="mouzhai"/>
</dataSource>
</environment>
</environments>
<!--配置好Mappers标签 Mybatis才知道去哪里找mapper映射文件-->
<!--有三种配置方法:
resource="cn/zhaiblog/dao/UserMapper.xml"
class="cn.zhaiblog.dao.UserMapper"
url="绝对路径 不会"
-->
<mappers>
<mapper class="cn.zhaiblog.dao.UserMapper"/>
</mappers>
</configuration>
-
编写Mybatis工具类
//工具类 获取sqlSessionFactory --> sqlSession public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory; static { //使用Mybatis获取sqlSessionFactory对象 String resource = "mybatis-config.xml"; try { InputStream resourceAsStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession(){ if (sqlSessionFactory!=null){ return sqlSessionFactory.openSession(); } return null; } }
2.3 编写代码
-
实体类
package cn.zhaiblog.pojo;
/**
* 实体类
*/
public class User {
private int id;
private String name;
private String pwd;
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public User() {
}
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接口
package cn.zhaiblog.dao;
import cn.zhaiblog.pojo.User;
import java.util.List;
public interface UserDao {
List<User> getUserList();
}
-
接口实现类(由原来的UserImpl转换为xml配置文件 UserMapper)
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--Namespace绑定一个dao/mapper接口-->
<mapper namespace="cn.zhaiblog.dao.UserMapper">
<!--查询语句 id:必须有,对应UserImpl实现类中的方法名 resultType返回类型:要是完整路径-->
<select id="getUserList" resultType="cn.zhaiblog.pojo.User">
select *
from mybatis.user
</select>
</mapper>
2.4 测试
注意点:org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): cn.zhaiblog.dao.UserMapper.getUserList
3. CRUD
Select
<!--
查询语句 id:必须有,对应UserImpl实现类中的方法名 resultType返回类型:要是完整路径 可以使用别名
如果是多个对象,用list封装,这里resultType也不用改成List,用对象即可
-->
<select id="getUserList" resultType="cn.zhaiblog.pojo.User">
select *
from mybatis.user
</select>
insert
<insert id="addUser" parameterType="cn.zhaiblog.pojo.User">
insert into user(id, name, pwd)
VALUES (#{id}, #{name}, #{pwd})
</insert>
update
<update id="updateUser" parameterType="cn.zhaiblog.pojo.User">
update user
set name = #{name},
pwd = #{pwd}
where id = #{id};
</update>
delete
<delete id="deleteUser" parameterType="int">
delete
from user
where id = #{id};
</delete>
4. 配置解析
4.1 核心配置文件
-
mybatis-config.xml
-
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
4.2 环境配置(environments)
尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
-
默认使用的环境 ID(比如:default=”development”)。
-
每个 environment 元素定义的环境 ID(比如:id=”development”)。
-
事务管理器的配置(比如:type=”JDBC”)。
-
数据源的配置(比如:type=”POOLED”)。
事务管理器(transactionManager)
在 MyBatis 中有两种类型的事务管理器(也就是 type=”[JDBC|MANAGED]”):
-
JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
-
MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为
数据源(dataSource)
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
-
大多数 MyBatis 应用程序会按示例中的例子来配置数据源。虽然数据源配置是可选的,但如果要启用延迟加载特性,就必须配置数据源。
有三种内建的数据源类型(也就是 type=”[UNPOOLED|POOLED|JNDI]”):
UNPOOLED:无连接池 对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。
POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。
JNDI:springboot自带连接池
4.3 属性(Properties)
<!--引入配置文件代替dataSource里的Property-->
<properties resource="db.properties">
<property name="username" value="mouzhai"/>
</properties>
<environment id="test">
<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>
4.4 类型别名(TypeAliases)
可以在xml中配置标签
<!--一个个定义别名-->
<typeAliases>
<typeAlias type="cn.zhaiblog.pojo.User" alias="User"></typeAlias>
</typeAliases>
<!--自定义包扫描 实体类非常多的时候推荐-->
<typeAliases>
<package name="cn.zhaiblog.pojo"/>
</typeAliases>
也可以在类上面加注解
@Alias("User")
public class User {
private int id;
private String name;
private String pwd;
}
4.5 映射器(Mapper)
<!--配置好Mappers标签 Mybatis才知道去哪里找mapper映射文件-->
<!--有四种配置方法:
resource="cn/zhaiblog/dao/UserMapper.xml"
class="cn.zhaiblog.dao.UserMapper"
url="绝对路径 不用它"
<package name = "">
-->
<mappers>
<mapper class="cn.zhaiblog.dao.UserMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="cn.zhaiblog.dao"/>
</mappers>
-
接口和他的Mapper配置必须同名
-
接口和他的mapper文件必须在同一个包下!
5. 解决属性名和字段名不一致的问题
5.1 方法一
/**
* 实体类
*/
public class User {
private int id;
private String name;
private String password;
}
// 给sql语句起个别名就可以了
<select id="getUserByID" resultType="User" parameterType="_int">
select id, name, pwd as password
from user
where id = #{id};
</select>
5.2 方法二 resultMap
结果集映射 resultMap
元素是 MyBatis 中最重要最强大的元素.
<!-- id就是名称 type就是映射出来的类型 -->
<resultMap id="UserMap" type="User">
<!--colnum数据库中的字段,property实体类中的属性-->
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserByID" resultMap="UserMap" parameterType="_int">
select *
from user
where id = #{id};
</select>
阿里巴巴规范手册推荐
规范手册推荐,不管是pojo类和查询结果字段是否匹配,一律使用resultMap映射,这样可以解耦,一个map对应一个查询
6. 日志
6.1 日志工厂
如果一个数据库操作,出现了异常,我们需要拍错,日志就是最好的助手!
曾经:sout , debug
现在:日志工厂
-
-
LOG4J(deprecated since 3.5.9)
-
LOG4J2
-
JDK_LOGGING
-
COMMONS_LOGGING
-
STDOUT_LOGGING
-
NO_LOGGING
<!-- 标准的日志工厂实现 -->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
6.2 log4j
-
导入log4j
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
-
配置文件
#将等级为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/zhai.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
- 简单实用
Logger logger = Logger.getLogger(UserMapperTest.class); @Test public void Log4jTest() { logger.info("info:进入了Log4JTest"); logger.debug("debug:进入了Log4JTest"); logger.error("error:进入了Log4JTest"); }
- 运行结果
7. 分页
思考:为什么要分页?
-
减少数据量
从startIndex开始查,每页显示pageSize个
语法:SELECT * FROM user limit startIndex,pageSize;
8. 多对一查询
方法一:子查询
<!--思路:
1: 查询所有的学生
2: 根据查询出来的学生tid,寻找对应的老师
-->
<select id="getAllStudent" resultMap="studentToTeacher">
select *
from student;
</select>
<resultMap id="studentToTeacher" type="cn.zhaiblog.pojo.Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--accociation 表示对象 collection 表示集合-->
<association property="teacher" column="tid" javaType="cn.zhaiblog.pojo.Teacher" select="getAllTeacher"/>
</resultMap>
<select id="getAllTeacher" resultType="cn.zhaiblog.pojo.Teacher">
select *
from teacher;
</select>
方法二:嵌套查询
<select id="getAllStudent" resultMap="studentToTeacher">
select s.id sid, s.name sname, s.tid stid, t.id tid, t.name tname
from student s,
teacher t
where s.tid = t.id;
</select>
<resultMap id="studentToTeacher" type="cn.zhaiblog.pojo.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="cn.zhaiblog.pojo.Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
回顾Mysql多对一查询方式:
-
子查询
-
连表查询
暂无评论内容