MyBatis的中文官方 : https://mybatis.org/mybatis-3/zh/index.html
W3School的Mybatis网站 : https://www.w3cschool.cn/mybatis/
介绍(Ibatis3就叫MyBatis)
MyBatis:是一款轻量级的ORM(对象-关系-映射)、半自动的持久层框架,
作用是:将原来的 JDBC 的SQL 与 JAVA代码的硬编译、高耦合转为SQL 与 JAVA分离:SQL语句有开发人员XML配置
功能边界清晰 :SQL的就写SQL,JAVA就写JAVA
MyBatis的规范
原生配置,pom-Dao层-interface-dao-config-domainMapper --实现类
新的方式,pom-Mapper层-interface-config-domainMapper --仅需接口
两者区别就是原生的方式必须要写实现类
注意事项:假如domain的属性名没有与sql的表字段名相同,就需要起别名了(就是如果想成功运行 就是接收的domain的属性名要与表的字段相同)
Mybatis接入流程:
导入Maven依赖 + 配置.xml + SqlMapper.xml
config.xml:核心全局配置文件:包含了数据源连接池信息、事务管理器信息、系统运行环境今昔
sqlMaper.xml:保存了所有的sql映射信息,将sql抽取出来
创建SqlSession对象(和connliction都非线程安全,每次使用,应该使用新的对象):代表了与数据库的一次会话
由于线程不安全,所以要pojo要实现Serializable接口
入门代码实现
入门代码结构
Mysql + Mybatis + Log4j 的Maven配置
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
先配置一个映射文件 UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD MyBatis 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="UserMapper">
<select id="findAll" resultType="com.zanglikun.domain.User">
select * from user
</select>
</mapper>
在配置一个 核心配置文件 sqlMapConfig.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="dev1">
<environment id="dev1">
<!-- 用的是那个事务管理器-->
<transactionManager type="JDBC"></transactionManager>
<!-- 数据源类型 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="740969606"/>
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 将来加载的时候 直接在下面引入就行 -->
<mappers>
<mapper resource="com/zanglikun/mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
创建一个数据库 名为:mybatis 内容如下:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL,
`username` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`password` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`age` int(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'zhangsan123', '123', 12);
INSERT INTO `user` VALUES (2, 'lisi456', '456', 45);
SET FOREIGN_KEY_CHECKS = 1;
测试代码
@Test
public void test1() throws IOException {
// 获取核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
// 使用核心配置文件获取Session工厂对象
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 获得Session 会话对象
SqlSession sqlSession = build.openSession();
// 使用 会话对象进行操作
List<Object> list = sqlSession.selectList("UserMapper.findAll");
System.out.println(list.get(0));
System.out.println(list.get(1));
// 释放资源
sqlSession.close();
}
测试结果:
配置文件介绍:
注意点
#{设置 parameterType后 可直接填对象的属性名}
mybatis 默认是用的JDBC事务,需要我们手动提交
// Mysql 最终要提交事务
sqlSession.commit();
MyBatis 核心配置文件
1 environments 标签
2 mappers 标签
3 proerties 标签
在 configuration 标签下引入
<properties resource="jdbc.properties"></properties>
......
<!--数据源类型-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
......
4 typeAliases 标签
<!-- 自定义别名 (放置的位置有顺序,请放置在properties标签后面) -->
<typeAliases>
<typeAlias type="com.zanglikun.domain.User" alias="user"></typeAlias>
</typeAliases>
同时 Mybatis 也为我们提供了 一些常用类型的别名
Mybatis API
这里 最容易被忽视,也是他的核心
SqlSessionFactoryBuilder 用来创建SqlSessionFactory的
SqlSessionFactory
openSession()
// 设置是否自动提交
openSession(boolean autoCommit)
SqlSession 会话对象 默认不会自动提交,需要手动提交 ,是Mybatis非常强大的类,可以控制 执行语句、提交事务、获取映射器实例的方法。
操作事务的方法
void commit()
void rollback()
初级进阶篇
我们实际生产过程中 不会使用 传统方式 :通过在Service实现层进行 创建 Resources读取核心配置文件,然后进行SqlSessionFactoryBuilder 进行创建 创建工厂对象 SqlSessionFactory ,然后创建出SqlSession对象,进行Sql的执行,等等!
所以 我们要是用 Mybatis 动态接口代理方式 ,需要遵守一下规范
具体实现方式
在通过获取SqlSession 获取的mapper对象使用 userMapper.findByid(1);进行查询,以及获取结果。
除了模式更变之外,我们 还需要引入 :
Dynamic SQL 即 动态SQL
常用 标签是 if、choose、trim、foreach、where
where 标签 :等同于where 1=1恒等式,条件判断时,自动地处理 and 或者 or 条件。
if 标签:实例:
<select id = "findAll" paramerType="string">
select * from user
<where>
<if test="username != null">
username = #{username}
</if>
</where>
</select>
foreach 标签
等价于 select * from user where username in (LIST)
<select id = "findAll" paramerType=="list">
select * from user
<where>
<foreach collection="list" open="age in(" close=")" item= "id" separator=",">
#{id}
</foreach>
</where>
</select>
include 标签 与 sql 标签 : 抽取的语句
<sql id = "ABC">select * from user</sql>
<select id = "findAll" paramerType="string">
<include refid = "ABC"></include>
<where>
<if test="username != null">
username = #{username}
</if>
</where>
</select>
trim 标签 : 一般都用于插入
- prefix:在trim标签内sql语句加上前缀
- suffix:在trim标签内sql语句加上后缀
- prefixOverrides:指定去除多余的前缀内容,如:prefixOverrides=“AND | OR”,去除trim标签内sql语句多余的前缀"and"或者"or"。
- suffixOverrides:指定去除多余的后缀内容。
<insert>
insert into user
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username != null">
username,
</if>
<if test="password != null">
username,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="username != null">
#{username,jdbcType=VARCHAR},
</if>
<if test="password != null">
#{password,jdbcType=VARCHAR},
</if>
</trim>
</insert>
set 标签: 一般用于更新 自动添加set关键字,剔除追加到条件末尾的任何不相关的逗号
注意事项:set关键字 使用 if 组合的时候 每个if 必须结尾有 逗号
<update id = "changeCompany" paramerType="com.zanglikun.pojo.Company">
update company_order
<set>
<if test="companyId != null">
company_id = #{companyId,jdbcType=BIGINT},
</if>
<if test="orderCreated != null">
order_created = #{orderCreated,jdbcType=TIMESTAMP},
</if>
</set>
where order_id = #{orderId,jdbcType=BIGINT}
</update>
#{}与${}的区别,面试题
#{}是预编译,而${}直接取出,有sql注入的风险的sql语句是与预编译 、是占位符形式的,然后执行的是将占位符复制的sql ,而${}直接是值,作用范围:字段名、表名不支持预编译,所以必须使用${}
Mybatis 核心配置文件深入
typeHandlets 无论是Mybatis 在预处理语句(PrepareStatement)中设置一个参数时,还是从结果集中取出一个值的时候,都会经过这个 类型转换器 将获取的值 以合适的方式转成Java类型。
当然直接说这个 肯定是难以理解的 我们以 实例需求 解决:
我们数据库一个字段是 bigInt 时间戳 但是 我们需要从数据库查出开的时候 是Java time包下的Date类型。
一个User对象 有个字段 birthday 类型是 Date类型
我们插入对象的时候,直接插入对象,就会出错。
解决办法:
自定义 TypeHandles
为什么BaseTypeHandle<T> ?
当我们继承BaseTypeHandel时候,指定了泛型后,必须重写的一部分方法 就是以此返回的。
package com.zanglikun.handler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
/**
* @author : zanglikun
* @date : 2021/3/17 16:49
* @Version: 1.0
* @Desc : 类型转换
*/
public class DateTypeHandler extends BaseTypeHandler<Date> {
// 将java类型 转换成 数据库需要的时间戳类型
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
long time = date.getTime();
preparedStatement.setLong(i,time);
}
// s 是sql查询结果的字段名称
// resultSet 是结果集
@Override
public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
long aLong = resultSet.getLong(s);
Date date = new Date(aLong);
return date;
}
// i 是sql结果的字段位置索引
// resultSet 是结果集
@Override
public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
long aLong = resultSet.getLong(i);
Date date = new Date(aLong);
return date;
}
// i 是sql结果的字段位置索引
// callableStatement 不是很清楚
@Override
public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
long aLong = callableStatement.getLong(i);
Date date = new Date(aLong);
return date;
}
}
<typeHandlers>
<typeHandler handler="com.zanglikun.handler.DateTypeHandler"></typeHandler>
</typeHandlers>
完成,将来遇到 时间戳 就可也映射成 Data了
Plugins 标签
Mybatis 会使用 第三方 PageHelper 插件 进行增强分页功能
导包
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.4</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>1.0</version>
</dependency>
配置文件引入
<!-- 插件 -->
<plugins>
<!-- PageHelper 5.0 之后的版本一律用 PageInterceptor 如果是4.0 请自行百度查找-->
<plugin interceptor="com.github.pagehelper.PageInterceptor">
</plugin>
</plugins>
使用 设置当前页、每页显示条数
PageHelper.startPage(page,pagesize); // 进行分页
PageHelper.clearPage();
PageHelper.startPage(page, pageSize,false); // 通过PageInfo得到的total是-1
PageHelper.startPage(page, pageSize,true); // 等价于 PageHelper.startPage(page, pageSize);
PageHelper.startPage(page, pageSize); // 此语句默认会有count计数 可通过PageInfo.getTotal(),得到查询的结果数。
PageHelper.orderBy("id desc");// 将结果查询的适合通过id 降序排列
总结
写到这里,必须要反思 这些标签 具体是干嘛的,不然,时间久了必忘记!!!
进阶内容,去看下 新文章:https://www.zanglikun.com/3320.html
注意 配置文件出错,请检查 文件顺序,如何看提示呢?配置文件出错,直接 run 项目 就会 抛一下问题:
"configuration" 的内容书询 必须按照下面顺序匹配 "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)"。
第三方平台不会及时更新本文最新内容。如果发现本文资料不全,可访问本人的Java博客搜索:标题关键字。以获取最新全部资料 ❤
评论(0)