Mybatis
持久层框架,方便填写sql语句
方便,帮助将数据存入数据库
传统的JDBC代码太复杂。简化、框架、自动化。
优点
- 简单易行
- 灵活
- sql和代码的分离,提高了可维护性
- 。。。
持久化
数据持久化
- 持久化就是将程序的数据在持久状态和顺势状态转化的过程
- 内存:断电即失
- 数据库(Jdbc),io文件持久化
持久层
Dao层,Service层,Controller层
- 完成持久化工作的代码块
- 层界限十分明显
1. Mybatis程序
1.1 搭建环境
- 搭建数据库
create database `mybatics`; use mybatics; create table `user`( `id` int(20) not null, `name` varchar(30) default null, `pwd` varchar(30) default null, primary key(`id`) )engine=InnoDB default charset=utf8; insert into `user`(`id`,`name`,`pwd`) values (1,'张三','123456'), (2,'李四','123456'), (3,'王五','123456')
新建项目
- 创建maven项目
- 更换自己的maven仓库
- 删除src目录
- 导入maven依赖
<dependencies> <!-- mysql驱动 --> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency> <!-- mybatis --> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> <!-- junit --> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> <scope>test</scope> </dependency> </dependencies>
1.2 创建模块
idea数据库连接
问题:
mysql8.0 需要重新导入8.0的jdbc的jar包
serverTimezone未配置
- 打开mysql命令行
// 显示时区信息 show variables like’%time_zone’; // 若显示为system --> 表示未设置时区 //设置时区 set global time_zone=’+8:00’;
编写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.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatics?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="888888"/> </dataSource> </environment> </environments> <mappers> <mapper resource="org/mybatis/example/BlogMapper.xml"/> </mappers> </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 MybatisUtils { private static SqlSessionFactory sqlSessionFactory; static{ try { //第一步:获取sqlSessionFactory对象 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); }catch (IOException e){ e.printStackTrace(); } } //从sqlSessionFactory获取sqlSession实例 public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); } }
1.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; } 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接口
public interface UserDao { List<User> getUserList(); }
- 接口实现类 : 由原来的Dap实现类重写方法的方式转为xml实现方式
<?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"> <!-- 绑定一个对于的Mapper接口 --> <mapper namespace="com.Rickduck.dao.UserDao"> <!--select查询语句--> <select id="getUserList" resultType="com.Rickduck.pojo.User"> select * from mybatis.user </select> </mapper>
1.4 测试
核心配置中配置mapper
junit单元测试
package com.Rickduck.dao; import com.Rickduck.pojo.User; import com.Rickduck.utils.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.junit.jupiter.api.Test; import java.util.List; public class MyTest { @Test public void test(){ //第一步:获得SqlSession SqlSession sqlSession = MybatisUtils.getSqlSession(); //执行Sql UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.getUserList(); for (User user : userList) { System.out.println(user); } sqlSession.close(); } }
需要注意的问题
- 配置文件是否已有注册
- 绑定接口是否有错
- 方法名是否有错
- 返回类型是否正确
- Maven导出资源是否有问题
- SqlSessionFactoryBuilder
- 负责创建SqlSessionFactory,一旦创建了SqlSessionFactory,就不再需要用它
- 方法作用域(局部方法变量)
- SqlSessionFactory
- 创建SqlSession,一旦被创建就应该在应用的运行期间一直存在
- 应用作用域(单例模式或静态单例模式)
- SqlSession
- 每个线程应该都有自己的SqlSession实例
- 线程不安全
- 请求或方法作用域
- 每收到HTTP请求,就可以打开SqlSession,返回一个响应,就关闭
- 关闭操作放在finall块中!!!
另外关于资源配置的问题:
<!-- 在build中配置resources,来防止我们资源导出失败的问题 --> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
2. CRUD
1.namespace
namespace中的包名跟Mapper接口的包名一致
2. select
选择、查询语句
- id : 方法名
- resultType : Sql语句执行的返回值
- parameterType : 参数类型
//第一步:获得SqlSession SqlSession sqlSession = MybatisUtils.getSqlSession(); //执行Sql UserMapper userMapper = sqlSession.getMapper(UserMapper.class); @Test public void select(){ try{ // 1. select * List<User> userList = userMapper.getUserList(); for (User user : userList) { System.out.println(user); } //2. selecById User user = userMapper.getUserById(1); System.out.println(user); }catch (Exception e){ e.printStackTrace(); }finally { //关闭sqlSession sqlSession.close(); } }
3. insert(增删改 需要提交事务)
@Test public void insertTest(){ //3. insert (增删改需要提交事务) int flag = userMapper.addUser(new User(4,"哈哈","123456")); //事务提交 sqlSession.commit(); //关闭sqlSession sqlSession.close(); }
4. update
5. delete
6.Map
实体类或数据库中的表、字段或者参数过多,可以考虑使用Map!
3. 配置解析
1.核心配置文件
mybatis-config.xml
MyBatis的配置文件会深深影响Mybatis星为的设置和属性信息
properties(属性) settings(设置) typeAliases(类型别名) typeHandlers(类型处理器) objectFactory(对象工厂) plugins(插件) environments(环境配置) environment(环境变量) transactionManager(事务管理器) dataSource(数据源) databaseIdProvider(数据库厂商标识) mappers(映射器)
2. 环境配置
可以配置多个环境,但每个sqlSessionFactory实例只能选择一个环境
默认事务管理器:JDBC
默认连接池:POOLED
3. 属性(properties)
可以通过properties属性实现引用配置文件(内部优先)
- 属性可外部配置动态替换
<!-- 引入外部配置文件 --> <properties resource="db.properties" > <property name="username" value=""/> <property name="password" value=""/> </properties>
4. 类型别名
- 实体类
- 包扫描
- 注解(实体类上添加@Alias("name") )
<typeAliases> <!-- 实体类起别名 --> <typeAlias type="com.Rickduck.pojo.User" alias="User" /> <!-- 包扫描起别名--> <package name="com.Rickduck.pojo"/> </typeAliases>
5. 设置
6. 映射器
MapperRegistry : 注册绑定我们的映射文件
方式一: xml配置
<mappers> <mapper resource="com/Rickduck/dao/UserMapper.xml"/> </mappers>
方式二: class文件绑定注册
<mappers> <mapper class="com.Rickduck.pojo.UserMapper" /> </mappers>
注意点:
- 接口和Mapper配置文件必须同名
- 接口和Mapper配置文件必须在同一包下
方式三:使用包扫描
<mappers> <package name="com.Rickduck.pojo"/> </mappers>
注意点:
- 接口和Mapper配置文件必须同名
- 接口和Mapper配置文件必须在同一包下
7. 生命周期和作用域
SqlSessionFactoryBuilder
- 一旦创建就不再需要
- 最佳作用域:局部变量
SqlSessionFactory
- 一旦创建旧应该一直存在(类似连接池)
- 最佳作用域:应用作用域
- 单例模式/静态单例模式
SqlSession
连接到连接池的一个请求
SqlSession非线程安全,不能被共享
最佳作用域:请求或方法作用
用完后断开
4. 解决属性名和字段名不一致的问题
resultMap
结果集映射
<mapper namespace="com.Rickduck.dao.UserMapper"> <!-- pojo类与数据库名字不一致可一一映射 --> <!-- 结果集映射 --> <resultMap id="UserMap" type="User"> <result column="id",property="id" /> <result column="name",property="name" /> <result column="pwd",property="password" /> </resultMap> <select id="getUserById" resultMap="UserMap"> select * from mybatis.user where id = #{id} </select> </mapper>
ResultMap
设计思想:对于简单语句不需要配置显示映射,复杂语句只需要描述他们的关系即可
5. 日志
5.1 日志工厂
- 出现异常、排错 需要日志!!
- 曾经:sout、debug
- 现在:日志工厂!
1609925677993
- mybatis-config.xml 在properties中添加:
- STDOUT_LOGGING : 标准日志输出
<settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>
5.2 Log4J
- log4J:可以控制日志信息的输出位置(控制台,组件,文件)
- 可以控制
输出格式
- 可以定义日志的
级别
,更加细致控制日志的生成过程 - 可通过一个
配置文件
配置而无需修改代码
- 导入log4j的包
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.14.0</version> </dependency>
- log4j.properties
- 配置log4j为日志实现
<settings> <setting name="logImpl" value="LOG4J" /> </settings>
- log4j的使用 测试运行
简单使用
在需要使用log4j的类中,导入包
import org.apache.log4j.logger
日志对象,参数为当前类的class
//日志对象 static Logger logger = Logger.getLogger(UserMapper.class); public void testLog4j(){ logger.info("info"); logger.debug("debug"); logger.error("error"); }
- 日志级别
logger.info("info"); logger.debug("debug"); logger.error("error");
6. 分页
6.1 使用Limit分页
- 减少数据的处理量
- 使用
limit
进行分页
-- 语法:select * from user limit startIndex,pageSize; select * from user limit 0,2;
利用Mybatis实现分页,核心SQL
- 接口
List<User> getUserByLimit(Map<String,Integer> map);
- Mapper.xml
<select id="getUserByLimit" parameterType="map" resultType="User"> select * from student.user limit #{startIndex},#{pageSize} </select>
- 测试
@Test public void getUserByLimit(){ //第一步:获得SqlSession SqlSession sqlSession = MybatisUtils.getSqlSession(); //执行Sql UserMapper userMapper = sqlSession.getMapper(UserMapper.class); HashMap<String, Integer> map = new HashMap<>(); map.put("startIndex",0); map.put("pageSize",2); List<User> userList = userMapper.getUserByLimit(map); for (User user : userList) { System.out.println(user); } sqlSession.close(); }
6.2 通过RowBound实现分页
- 接口
List<User> getUserByRowBounds();
- mapper.xml
<select id="getUserByRowBounds" resultMap="UserMap"> select * from mybatis.user </select>
6.3 分页插件
8. 使用注解开发
8.1 面向接口编程
- 根本原因:解耦
三个面向区别
- 面向对象 :以对象为单位,考虑其属性及方法
- 面向过程 :以具体流程(事务过程)为单位,考虑其实现
- 接口设计与非接口设计是针对复用技术而言,更多体现对系统的整体架构
8.2 使用注解开发
是可以使用Java注解来配置
public interface UserMapper{ @Select("select * ftom student.user") List<User> getUsers(); }