- MyBatis笔记
- 一.概述
- 二. MyBatis 环境搭建
- 三.创建Mybatis项目步骤
- 步骤:
- 1.根据需求设计一个类与数据库的表
- 2.接口(Mapper),实现对类的一些操作
- 3.全局配置文件(mybatis.xml)配置信息
- `< typeAliases>`为类定义别名
- 配置`< mapper>`(添加SQL映射文件)
- 设置
- Mybatis日志
- 配置环境
- 创建config. properties(存储与数据库连接的信息)
- 引入config. properties
- 4.接口对应的配置文件(AdminMapper.xml)
- 驼峰映射
- 封装步骤
- 单元测试
- 类型别名
- 参数传递
- 1.简单的参数形式不需要使用 parameterType 参数定义
- 2. 多个参数使用@Param(“id”)绑定
- 3.传入复杂的参数,使用Map对象传递
- 结果处理
- 简单类型输出映射
- POJO对象输出映射
- 多表关联处理查询结果集
MyBatis原是Apache的一个开源项目iBatis, 2010年由Apache Software Foundation 迁移到了 Google Code, iBatis3.x正式更名为MyBatis。是 一个基于Java的持久层框架。 iBatis提供的持久层框架包括SQL Maps和Data Access Objects (DAO)。
MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJO(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录,是 一种 ORM(ORM Object Relational Mapping 对象关系映射)实现. Mybatis 将基本的 JDBC 常用接口封装,对外提供操作即可.
- 是一个ORM框架.
ORM(Object Relational Mapping)对象关系映射 - 封装了一些关于数据库操作的接口,代替了JDBC
- 对jdbc进行了封装,简化了其操作
Mybatis 中文官网: mybatis – MyBatis 3 | 入门
既然mybatis封装了JDBC,那么来看一下传统JDBC和MyBatis的区别
我们使用mybatis做一个小demo来看一下和传统JDBC的区别
使用maven构建一个Mybatis,在这里我使用的工具是IDEA
传统JDBC:
- 加载数据库驱动
- 创建并获取数据库链接
- 创建 statement 对象
- 拼写 sql 语句
- 设置 sql 语句中的占位符的值 (使用预编译可以防止sql注入)
- 执行 sql 语句并获取结果
- 对 sql 执行结果进行解析处理
- 释放资源
JDBC的编程问题
- 数据库连接的创建、释放频繁造成系统资源浪费从而影响系统性能,如果使 用数据库连接池可解决该问题。
- SQL 语句编写在 Java 代码中,这种硬编码造成代码不易维护,当 SQL 变动 时需要修改 java 源代码。
- 使用 preparedStatement 向占位符传参数存在硬编码,因为 SQL 语句的 where 条件中占位符的个数可能会变化,修改 SQL 还要修改 Java 源代码, 系统不易维护.
- 对结果集解析存在硬编码,SQL 语句变化导致解析代码变化,系统不易维护。
-
先创建一个maven的项目(搭建maven:https://blog.csdn.net/lanleihhh/article/details/120978091)
-
导入mybatis/mysql的坐标(maven仓库下载:https://mvnrepository.com/)
复制后粘贴到中
org.mybatis
mybatis
3.4.6
mysql
mysql-connector-java
8.0.25
点击’M’形状的按钮安装jar包
我们可以使用日志组件(log4j)来记录程序的信息,引入log4j的坐标
log4j
log4j
1.2.17
注意:引入log4j的坐标后,还需在resources文件中添加配置文件:log4j.properties
log4j.rootLogger = debug,stdout,D
#System out Console
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%p] %d{yyyy-MM-dd HH:mm:ss,SSS} %m%n
#System out File
log4j.appender.D = org.apache.log4j.FileAppender
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
# 这里设置打印日志的文件路径
log4j.appender.D.File = E://logs/mybatisLog/LogMybatisDemo.log
log4j.appender.D.Append = true
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] -[%l] %m%n
创建 MyBatis 全局配置文件 MyBatis 的配置文件包含了对 MyBatis 行为的设置信息。
配置文档的顶层 结构如下(标签需要按照特定顺序排放):
- configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- environment(环境变量)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
如下:
三.创建Mybatis项目步骤 步骤: 1.根据需求设计一个类与数据库的表
Java类:
package com.ffyc.mybatispro.model;
public class Admin {
private int id;
private String account;
private String password;
private String sex;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Admin{" +
"id=" + id +
", account='" + account + ''' +
", password='" + password + ''' +
", sex='" + sex + ''' +
", userName='" + userName + ''' +
'}';
}
}
数据库表:
CREATE DATAbase mybatis_db CHARSET utf8 CREATE TABLE admin( id INT PRIMARY KEY AUTO_INCREMENT, sex CHAr(1), account VARCHAr(20), PASSWORD VARCHAr(20) )2.接口(Mapper),实现对类的一些操作
package com.ffyc.mybatispro.mapper;
import com.ffyc.mybatispro.model.Admin;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface AdminMapper {
//插入
void saveAdmin(Admin admin);
//更新
void updateAdmin(Admin admin);
//删除
void deleteAdmin(int AdminId);
//修改
Admin findAdminById(int AdminId);
//传多个参数,使用注解标签@Param("acc") acc:传向xml文件中 #{acc}
Admin findAdmin(@Param("acc")String account,@Param("sex")String sex);
//传入键值对参数
Admin findAdmin(Map map);
//查询所有管理员对象
List findAllAdmin();
//查询管理员总人数
int adminCount();
}
3.全局配置文件(mybatis.xml)配置信息
几个.xml配置文件的区别
< typeAliases>为类定义别名- type:全类名
- alias:别名
配置< mapper>(添加SQL映射文件)
设置 Mybatis日志
Mybatis 内置的日志工厂提供日志功能,具体的日志实现有以下几种方式:
- SLF4J
- LOG4J
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING
- NO_LOGGING
具体选择哪个日志实现由 MyBatis 的内置日志工厂确定。它会使用最先找到的配置日志
配置环境
创建config. properties(存储与数据库连接的信息)
driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/mybatis_db?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username=root password=lanlei6843引入config. properties
4.接口对应的配置文件(AdminMapper.xml)
insert into admin(account,password,sex,user_name)values(#{account},#{password},#{sex},#{userName})
测试方法:saveAdmin()
package com.ffyc.mybatispro.test;
import com.ffyc.mybatispro.mapper.AdminMapper;
import com.ffyc.mybatispro.model.Admin;
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;
import java.io.Reader;
public class Test1 {
public static void main(String[] args) throws IOException {
Admin admin = new Admin();
admin.setAccount("admin");
admin.setPassword("123");
admin.setSex("男");
InputStream reader = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession sqlSession= sqlSessionFactory.openSession();
//获得映射接口的代理对象
//MapperProxy动态实现了自定义接口
//adminMapper对象实质是MapperProxy对象 org.apache.ibatis.binding.MapperProxy@79ad8b2f
//使用代理对象
AdminMapper adminMapper = sqlSession.getMapper(AdminMapper.class);
adminMapper.saveAdmin(admin);
sqlSession.commit();//提交事务
sqlSession.close();//关闭与数据库会话连接
}
}
运行一下:
查看数据库:
我们使用另一中传值方式
insert into admin(account,password,sex)values('${account}','${password}','${sex}')
运行:
传列: ${属性名}
传值:
'${属性名}':${} 拼接符,会传入参数字符串,取值以后再去编译 SQL 语句,$方式无法防止sql注入
#{属性名} :#{} 占位符,是经过预编译的,编译好 SQL 语句再取值,#方式能够防止 sql 注入
values('','',''):字符串拼接方式
values(?,?,?):预编译,是安全的,可以防止sql注入
注意:MyBatis 排序时使用 order by 动态参数时需要注意,用$而不是#
驼峰映射
在mybatis中默认java属性名和数据库字段名一一对应
如:
java: account
mysql:account
但两者定义语法不同
- java属性采用小驼峰(userName)
- 数据字段采用下划线(user_name)
很多时候没法将Java属性与数据库字段定义为相同的,因为要遵循规范
解决方法:
-
在sql语句中使用As设置别名,如(user_name As userName),设置与Java属性相同
-
mybatis的settings配置中有一个name为mapUnderscoreToCamelCase的参数,默认是false,设置为true,即可开启驼峰映射
可以从Java属性userName映射到数据库字段user_name,方便了很多
我们测试一下
在数据库中修改表列命名为经典下划线
-- 修改列名 ALTER TABLE admin CHANGE PASSWORD pass_word VARCHAr(20)
在java中修改属性
//private String password;原属性 private String passWord;
sql映射中修改sql语句
insert into admin(account,pass_word,sex)values(#{account},#{passWord},#{sex})
测试运行:
成功运行了,这就是驼峰映射
我们将属性与字段再修改为原来的password
封装步骤将步骤繁多的流程封装起来,我们使用的时候直接访问该封装类的方法
package com.ffyc.mybatispro.util;
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 MybatisUtil {
static SqlSessionFactory sqlSessionFactory = null;
static {
InputStream reader = null;
try {
reader = Resources.getResourceAsStream("mybatis.xml");
} catch (IOException e) {
e.printStackTrace();
}
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
}
public static SqlSession getSqlSession(){//返回sqlSession对象
return sqlSessionFactory.openSession();
}
}
单元测试
概念
-
java单元测试是最小的功能单元测试代码
-
单元测试就是针对某个Java方法的测试
-
java程序的最小功能单元是方法
使用单元测试的好处
- 不用再在main()方法中一个一个调用,测试完毕后再删除
- 确保单个方法正常运行
- 每个单元测试用例相对独立,不需要添加额外语句
- 只需查看测试结果,就可以了解整个项目的的方法接口是否通畅
我们借助juit工具进行测试
先在pom.xml中依赖单元测试的jar包,将其jar包下载到本地仓库中,然后依赖它
junit
junit
4.12
provided
在想要测试的方法前添加注解标签@Test,如下:
@Test
public void update(){
Admin admin = new Admin();
admin.setAccount("admin");
admin.setPassword("123456");
admin.setSex("男");
//创建SqlSession对象
SqlSession sqlSession = MybatisUtil.getSqlSession();
//获取代理对象
AdminMapper mapper = sqlSession.getMapper(AdminMapper.class);
mapper.updateAdmin(admin);
sqlSession.commit();//提交事务
sqlSession.close();//关闭连接
}
类型别名
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
当这样配置时,Admin可以在任何使用 com.ffyc.mybatispro.model.Admin 的地方。
可以在mybatis的jar包中找org.apache.ibatis.type.TypeAliasRegistry
里面定义了各种基本类型和引用类型的别名;如图
下面是mybatis为Java类库中的一些类和简单类型定义的别名
| 别名 | 映射的类型 |
|---|---|
| _byte | byte |
| _long | long |
| _short | short |
| _int | int |
| _integer | int |
| _double | double |
| _float | float |
| _boolean | boolean |
| string | String |
| byte | Byte |
| long | Long |
| short | Short |
| int | Integer |
| integer | Integer |
| double | Double |
| float | Float |
| boolean | Boolean |
| date | Date |
| decimal | BigDecimal |
| bigdecimal | BigDecimal |
| object | Object |
| map | Map |
| hashmap | HashMap |
| list | List |
| arraylist | ArrayList |
| collection | Collection |
| iterator | Iterator |
如:
//删除
void deleteAdmin(int AdminId);
//修改
Admin findAdminById(int AdminId);
delete from admin where id=#{id}
2. 多个参数使用@Param(“id”)绑定
Mapper接口方法
//传多个参数,使用注解标签@Param("acc") acc:传向xml文件中 #{acc}
Admin findAdmin(@Param("acc")String account,@Param("sex")String sex);
xml中的实现
java测试代码
@Test
public void find3(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
AdminMapper mapper = sqlSession.getMapper(AdminMapper.class);
Admin admin = mapper.findAdmin("admin","男");
System.out.println(admin);
sqlSession.commit();
sqlSession.close();
}
3.传入复杂的参数,使用Map对象传递
Mapper接口方法
//传入键值对参数
Admin findAdmin(Map map);
xml中的实现
对于简单类型可不写parameterType属性,使用Java类库中的类作为参数时,使用mybatis为其定义的别名
这里可以通过mybatis3官方手册查看,XML配置–>类型别名https://mybatis.org/mybatis-3/zh/configuration.html#typeAliases
java测试代码
@Test
public void find4(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
AdminMapper mapper = sqlSession.getMapper(AdminMapper.class);
Map map = new HashMap<>();
map.put("acc", "admin");
map.put("sex", "男");
Admin admin = mapper.findAdmin(map);
System.out.println(admin);
sqlSession.commit();
sqlSession.close();
}
结果处理
简单类型输出映射
返回基本类型
//查询管理员总人数
int adminCount();
@Test
public void find6(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
AdminMapper mapper = sqlSession.getMapper(AdminMapper.class);
int count = mapper.adminCount();
System.out.println("管理员总人数:"+count);
sqlSession.commit();
sqlSession.close();
}
POJO对象输出映射
- 如果表中的类名与类中的属性名完全相同,mybatis会自动将查询结果封装 到POJO对象中
- 如果java中使用标准驼峰命名,数据库中使用下划线连接命名,可以开启全局设置实现自动转换
resultMap:
- resutlMap 的 id 属性是 resutlMap 的唯一标识
- resutlMap 的 id 属性是映射的 POJO 类
- id 标签映射主键,result 标签映射非主键
- property 设置 POJO 的属性名称,column 映射查询结果的列名称
将admin表中列名password修改为pass_word
定义resultMap
多表关联处理查询结果集
-
association – 复杂类型联合
许多查询结果合成这个类型 一对一结果映射
association 能引用自身, 或者从其它地方引用
处理一个类型的关系(类)
-
collection – 复杂类型集合 嵌套结果映射
collection 能引用自身, 或者从其它地方引用 多对一与一对多
处理一对多关联(集合)
-
部门与员工一对多
-
多个员工对应一个部门(多对一)
-
package com.ffyc.mybatisdemo.mapper;
import com.ffyc.mybatisdemo.model.Dept;
import java.util.List;
public interface DeptMapper {
//根据id查部门
Dept findDeptById(int id);
//查所有部门
List findDeptList();
}
sql映射文件
测试根据id查部门
@Test
public void findDept(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
Dept dept = mapper.findDeptById(1);
List deptList = dept.getEmployeeList();
System.out.println("部门"+dept.getName());
for(Employee employee : deptList){
System.out.println("所属员工:"+employee.getName());
}
sqlSession.commit();
sqlSession.close();
}
测试查所有部门
@Test
public void findDeptList(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
List depts = mapper.findDeptList();
for(Dept dept : depts){
System.out.println("部门名称:"+dept.getName());
for(Employee emp : dept.getEmployeeList()){
System.out.println("部门职工:"+emp.getName());
}
System.out.println("操作人:"+dept.getAdmin().getAccount());
}
sqlSession.commit();
sqlSession.close();
}



