Mybatis
环境
JDK1.8
Mysql 5.7
maven3.6.1
IDEA
已学:
jdbc
mysql
Java基础
Maven
Junit
SSM框架:配置文件,官方文档
MyBatis 是一款优秀的持久层框架
它支持自定义 SQL、存储过程以及高级映射
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
Maven仓库:
org.mybatis
mybatis
3.5.5
持久化:
数据持久化
持久化就是将程序的数据在持久状态和瞬时状态转化的过程
内存:断电即失
数据库(jdbc)io文件持久化
生活:冷藏,罐头
为什么需要持久化
有一些对象不能让他丢掉
内存贵
持久层
Dao层,Service层,Controller层
完成持久化工作的代码块
层界限十分明显
为什么需要Mybatis
方便
传统的JDBC代码太复杂了,简化,框架,自动化
帮助程序员将数据存入到数据库
不用Mybatis也可以。更容易上手。技术没有高低之分
优点
简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
提供映射标签,支持对象与数据库的orm字段关系映射
提供对象关系映射标签,支持对象关系组建维护
提供xml标签,支持编写动态sql。
最重要的一点:使用的人多
第一个Mybatis程序
搭建环境
搭建数据库
CREATE DATABASE mybatis;
use mybatis;
CREATE TABLE user(
id INT(20) not null PRIMARY KEY,
name VARCHAR(30) DEFAULT NULL,
pwd VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO user (id,name,pwd) VALUES
(1,‘狂神’,‘123456’),
(2,‘张三’,‘123456’),
(3,‘李四’,‘123890’)
新建项目
新建一个普通的maven项目
删除src目录
导入maven依赖
org.mybatis
mybatis
3.5.5
mysql
mysql-connector-java
8.0.21
junit
junit
4.13
test
src/main/resources
**/*.properties
**/*.xml
src/main/java
**/*.properties
**/*.xml
true
创建一个模块
配置核心文件
/p>
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
编写工具类
package com.company.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;
public class MybatisUtils {
//sqlSessionFactory—>SessionFactory
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();
}
}
编写代码
实体类
package com.company.pojo;
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接口
package com.company.dao;
import com.company.pojo.User;
import java.util.List;
public interface UserDao {
List getUserList();
}
接口实现类由原来的UserDaoImpl转变位一个Mapper配置文件
/p>
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
select * from mybatis.user;
测试
核心文件配置mapper
junit测试
@Test
public void test(){
//获取session对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//方式一,getmapper
UserDao mapper = sqlSession.getMapper(UserDao.class);
List userList = mapper.getUserList();
//方式二,
List userList = sqlSession.selectList("com.company.dao.UserDao.getUserList");
for (User user : userList) {
System.out.println(user);
}
//关闭
sqlSession.close();
}
出现资源导出失败或编码问题
pom文件增加一下内容
src/main/resources
**/*.properties
**/*.xml
src/main/java
**/*.properties
**/*.xml
true
UTF-8
可能遇到的问题
配置文件没有注册
绑定接口错误
方法名不对
返回类型不对
Maven导出资源问题
CRUD
namespace
namespace中的包名要和Da/mapper接口的包一致
select
查询语句
id:就是对应的namespace中的方法名;
resultType:Sql语句执行的返回值!
parameterType:参数类型!
接口
package com.company.dao;
import com.company.pojo.User;
import java.util.List;
public interface UserMapper {
List getUserList();
//根据id查询用户
User getUserById(int id);
}
mapper绑定
/p>
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
select * from mybatis.user
/*定义sql*/
select * from mybatis.user where id = #{id};
注册
/p>
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
增删改需要提交事务
package com.company.dao;
import com.company.pojo.User;
import java.util.List;
public interface UserMapper {
List getUserList();
//根据id查询用户
User getUserById(int id);
//插入一个用户
int addUser(User user);
//修改用户
int updateUser(User user);
//删除用户
int deleteUser(int id);
}
/p>
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
select * from mybatis.user;
/*定义sql*/
select * from mybatis.user where id = #{id};
insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd});
update mybatis.user set name=#{name},pwd=#{pwd} where id =#{id}
delete from mybatis.user where id=#{id};
package com.company.dao;
import com.company.pojo.User;
import com.company.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserDaoTest {
@Test
public void test(){
//获取session对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
/*//方式一,getmapper
UserDao mapper = sqlSession.getMapper(UserDao.class);
List userList = mapper.getUserList();*/
//方式二,
List userList = sqlSession.selectList("com.company.dao.UserMapper.getUserList");
for (User user : userList) {
System.out.println(user);
}
//关闭
sqlSession.close();
}
@Test
public void getUserById(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserById(1);
System.out.println(user);
sqlSession.close();
}
//增删改需要提交事务
@Test
public void addUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res = mapper.addUser(new User(6, "ee", "223"));
if(res>0){
System.out.println("success");
}
//提交事务
sqlSession.commit();
sqlSession.close();
}
@Test
public void updateUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser(new User(6,"hhh","rrr"));
//提交事务
sqlSession.commit();
sqlSession.close();
}
@Test
public void deleteUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteUser(6);
//提交事务
sqlSession.commit();
sqlSession.close();
}
}
分析错误
标签不要匹配错
resource绑定mapper,需要匹配路径
程序配置文件必须规范
Map和模糊查询扩展
map
假设,我们的实体类,或者数据库中的表,字段或者参数过多,我们应当考虑使用map
//万能map
int addUser2(Map map);
insert into mybatis.user (id,name,pwd) values (#{userId},#{userName},#{passWord});
@Test
public void addUser2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map map = new HashMap<>();
map.put("userId","5");
map.put("userName","5");
map.put("passWord","5");
mapper.addUser2(map);
//提交事务
sqlSession.commit();
sqlSession.close();
}
map传递参数,直接在sql中取出key即可
对象传递参数,直接在sql中取对象的属性即可
只有一个基本类型参数的情况下,可以直接在sql取到
多个参数用Map,或者注解
模糊查询
List getUserLike(String value);
select * from mybatis.user where name like #{value};
@Test
public void getUserLike(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List list = mapper.getUserLike("%李%");
list.forEach(System.out::println);
sqlSession.close();
}
java代码执行的时候,传递通配符%xx%
在sql中拼接中使用通配符,注意避免sql注入
配置解析
核心配置文件
mybatis-config.xml
Mybatis的配置文件包含了会深深影响Mybatis行为的设置和属性信息
configuration(配置)
环境配置
Mybatis可以配置成适应多种环境
不过要记住:尽管可以配置多个环境,但每个SqlsessionFactory实例只能选择一种环境
学会使用配置多套运行环境
Mybatis默认的事务管理器就是JDBC,连接池:POOLED
属性(properties)
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置
编写一个配置文件
db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
username=root
password=123456
在核心配置文件种引入,注意XML中的标签是由顺序的
可以直接引入外部文件
/p>
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
可以在其中增加一些属性配置
如果两个文件由同一个字段,优先使用外部配置
类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean
每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。见下面的例子:
@Alias("author")
public class Author {
...
}
实体类比较少的时候,使用第一种方式
如果实体类十分多,建议使用第二种
第一种可以DIY别名,第二种则不行,如果非要改,需要在实体上增加注解
设置(settings)
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为
其他配置
plugins插件
mybatis-generator-core
mybatis-plus
通用mapper
映射器(mappers)
既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。
//接口和Mapper配置文件必须同名,且必须在同一个包下
//接口和Mapper配置文件必须同名,且必须在同一个包下
这些配置会告诉 MyBatis 去哪里找映射文件,剩下的细节就应该是每个 SQL 映射文件
作用域(Scope)和生命周期
作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。
提示 对象生命周期和依赖注入框架
依赖注入框架可以创建线程安全的、基于事务的 SqlSession 和映射器,并将它们直接注入到你的 bean 中,因此可以直接忽略它们的生命周期。 如果对如何通过依赖注入框架使用 MyBatis 感兴趣,可以研究一下 MyBatis-Spring 或 MyBatis-Guice 两个子项目。
SqlSessionFactoryBuilder
这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。
因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
SqlSessionFactory
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
因此 SqlSessionFactory 的最佳作用域是应用作用域。
有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
SqlSession
每个线程都应该有它自己的 SqlSession 实例。
SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
用完之后,需要赶紧关闭,否则资源会被占用
解决属性名和字段名不一致的问题
解决办法
起别名
select id,name,pwd as password from mybatis.user
resultMap
结果集映射
字段 idname pwd
属性 id name password
/*定义sql*/
select * from mybatis.user where id = #{id};
结果映射
resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份resultMap 能够代替实现同等功能的数千行代码。
ResultMap 的设计思想是,对简单的语句做到零配置,
对于复杂一点的语句,只需要描述语句之间的关系就行了。
ResultMap 的优秀之处——你完全可以不用显式地配置它们。
日志
日志工厂
如果一个数据库操作,出现了异常,我们需要排错,日志就是最好的助手
曾经:sout,debug
现在:日志工厂
logImpl
指定 MyBatis 所用日志的具体实现,未指定时将自动查找。
SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING
未设置
SLF4J
LOG4J 【掌握】
LOG4J2
JDK_LOGGING
COMMONS_LOGGING
STDOUT_LOGGING 【掌握】
NO_LOGGING
在Mybatis具体使用哪个日志实现,在设置中指定
STDOUT_LOGGING标准日志输出
在Mybatis核心配置文件中,配置我们的日志
LOG4J
什么是LOG4J
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;
我们也可以控制每一条日志的输出格式;
通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程
可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码
先导入包
log4j
log4j
1.2.17
log4j的配置文件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 = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%c]-%m%n
### 文件输出的相关设置###
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File = ./log/ming.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为日志的实现
log4j的使用,直接测试运行查询
简单使用
在要使用Log4j的类中,导入包import org.apache.log4j.Logger;
日志对象加载参数为当前类的class
日志级别
logger.info("info:进入了testLog4j");
logger.debug("debug:进入了testLog4j");
logger.error("error:进入了testLog4j");