MyBatis
MyBatis是半自动化的ORM框架,本质是使用Java语言完成数据库操作
ORM:Object Relational Mapping,对象关系映射,是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术
关系数据库:基于数据关系模型的数字数据库,许多关系数据库系统可以选择使用SQL来查询和维护数据库
关系模型:将数据组织到列和行的一个或多个表,并具有标识每行的唯一键;行也称为记录或元组,列也称为属性(建议看表辅助理解);通常每个表表示一个实体类,行表示该类型的实体的实例,列表示实例对应属性的值
定义
持久层框架
持久层:完成持久化工作的代码块,即DAO层
持久化:将程序、数据在持久状态和瞬时状态间转换的机制,即把数据(如内存中的对象)保存到可永久保存的设备中
JDBC、文件IO都是持久化的机制
优点
帮助程序员将数据存入数据库
减少重复代码,提高开发效率
解除SQL与程序代码的耦合,易维护,易单元测试
提供XML标签,支持动态编写SQL
使用流程
1.连接数据库
2.在pom.xml中导入JAR包
3.编写MyBatis核心配置文件
4.编写MyBatis工具类,来获取SqlSession
5.编写POJO
6.编写interface以及对应的Mapper.xml配置文件
7.编写测试类
XML配置文件(mybatis-config.xml)src/main/resources
<?xml version="1.0" encoding="UTF-8" ?><!--标签是有顺序的,不能在随意位置写-->
<!--引入外部配置文件,因为在同一包下,直接写文件的名字即可-->
<!--第一种写法:直接导入配置文件,文件中写好配置
<properties resource="db.properties"/>
-->
<properties resource="db.properties">
<property name="username" value="root"/>
</properties>
<!--1.给实体类起别名
<typeAliases>
<typeAlias type="cn.edu.hbue.User" alias="User"/>
</typeAliases>
-->
<!--2.指定包名,包内的POJO(Java Bean)的bean为别名,如User实体类,user为别名(大小写不区分,最好小写)-->
<typeAliases>
<package name="cn.edu.hbue.lzk.pojo"/>
</typeAliases>
<environments default="development"><!--默认的选择的环境为development-->
<environment id="development"><!--环境变量,开发模式-->
<transactionManager type="JDBC"/><!--事物管理器,对一系列操作进行管理;事物:包含一个或多个SQL语句,是逻辑管理的工作单元-->
<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>
</environments>
<!--3.使用包进行绑定注册映射器-->
<mappers>
<package name="cn.edu.hbue.lzk.dao"/>
</mappers>
注意:在xml的配置文件中,元素有先后顺序,可点击报错信息查看
environments元素
-
作用:配置MyBatis多套运行环境,必须指定其中一个默认的运行环境
-
子元素environment(一套运行环境)
-
transactionManager事务管理器
事务:用户定义的数据库操作序列,这些操作要么全做,要么全不做 注:增删改一定能要提交事务sqlSession.commit()-
JDBC
使用JDBC的提交和回滚设置,依赖从数据源获得的连接来管理事务作用域
-
MANAGED
几乎什么都没做
-
-
dataSource数据源
定义:使用标准的JDBC数据源接口来配置JDBC连接对象的资源
示例:
注:示例使用了db.properties配置-
property属性
-
name
driver
url
username
password -
value
-
优化:在同一路径下创建db.properties
db.properties:
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username = root
password = 123456
-
-
-
properties元素
-
作用:给系统配置一些运行参数,不在Java代码中,好处在于防变参数修改,不会引起代码重新编译
-
优先级顺序
- 先读取properties元素体内指定的属性
- 根据properties元素中resource属性读取路径下属性文件
- 最后读取最为方法传递的属性,并覆盖之前读过的同名属性
typeAlias元素
即,类型别名
-
作用:为Java类型设置一个缩写名字,仅用于XML配置,;意在降低冗余的全限定类名书写
全限定类名:包名+类型名
-
使用方法1:给实体类起别名
注:一般不区分大小写 -
使用方法2:指定包名,包内的Java Bean,bean为别名
-
使用方法3:在2的基础上,直接在POJO代码上添加注解
@Alias(“user”)
public class User {
private int id;
private String name;
private String pwd;
mappers元素
即,映射器
-
作用:告诉MyBatis去哪里找映射文件(映射文件包含了SQL语句)
-
使用方法1:相对于类路径的资源引用
注: Java中"/"和"."的区别 前者用于查找文件,如***.xml 后者是Java包命名的写法 -
使用方法2:class文件绑定注册
-
使用方法3:包进行绑定注册
其他元素
-
mapUnderscoreToCamelCase驼峰命名自动映射
- 定义:将数据库列名A_COLUMN映射到经典JAVA属性名aColumn
-
cacheEnable开启全局缓存
-
typeHandlers类型处理器
-
objectFactory对象工厂
-
plugins插件
-
databaseIdProvider数据库厂商标识
作用域和生命周期
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,SqlSession完全包含面向数据库执行的SQL命令所需的所有方法
//实现事务的自动提交
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession(true);
}
}
SqlSessionFactoryBuilder
static {
try {
//获取SqlSessionFactory对象
String resource = “mybatis-config.xml”;
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch ( IOException e ){
e.printStackTrace();
}
}
- 作用:创建SqlSessionFactory,一旦创建SqlSessionFactory就不需要它
- 作用域:方法作用域,即局部方法变量
SqlSessionFactory
- 作用:可以被认为是一个数据库连接池,创建SqlSession接口对象;一被创建就会在Mybatis应用的运行期间一直存在
- 作用域:应用作用域,使用单例模式,防止数据库连接资源耗尽
SqlSession
- 作用:相当于一个数据库连接,代表一个请求;每个线程都有SqlSession实例,SqlSession实例是不安全的,不能被共享
- 作用域:方法作用域,即局部方法变量
ResultMap(最强大的元素)
作用:解决实体类属性名与数据库表中的字段名不一致
使用方法1:在映射文件中使用元素
select * from user where id = #{id}-
子元素
- property:实体类的属性名
- column:数据表的列名
方法2:不使用ResultMap,在SQL语句中使用as,为字段起别名
select id, name, pwd as password where id = #{id}
日志
作用:控制日志信息输送的目的地,如果应用程序出现问题,日志记录可以定位问题
Log4j:Apache开源项目,Java日志
-
使用步骤①:在pom.xml中导包
log4j log4j 1.2.17 -
使用步骤②:在src/main/resources下创建配置文件,命名为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=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/lzk.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 -
使用步骤③:在同一目录下的mybatis-config.xml配置
分页
作用:降低数据处理量,一边拥有较高的效率
方法一:在SQL语句中使用limit实现分页
-
模板:select * from table limit i, n
- i:查询结果的索引值(默认从0开始),若只有参数i,则检索前i个数据
- n:查询结果返回的数量,若n=-1,则检索索引值i以及其后所有的数据
方法二:RowBounds实现分页
@Test
public void testGetUserByRowBounds(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//RowBounds实现,第一个参数为查询索引,第二个参数为结果返回数量
RowBounds rowBounds = new RowBounds(1, 2);
List<User> userList = sqlSession.selectList("cn.edu.hbue.lzk.dao.UserMapper.getUserByRowBounds",null,rowBounds);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
-
关键代码:RowBounds rowBounds = new RowBounds(offset,limit)
- offset:偏移量,起始为0
- limit:限制条数
方法三:分页插件PageHelper
方法四:MyBatis-plus
注解开发
使用步骤
-
①在接口添加注解
-
接口的特点
- 面向接口编程解耦、可扩展、提高复用
- 一个接口含有方法和属性
- 方法属于public abstract(无需写)
- 属性为静态常量public static final(无需写)
- 实现方法时,必须将方法声明public
- 每个类可实现多个接口,但每个类只能继承一个类
- 接口可继承多个接口
- Java语言利用Java机制实现C++多继承的大部分功能
-
注解
-
@Select
- e.g.:@Select(“select * from user where id = #{id}”)
-
@Insert
-
@Update
-
@Delete
-
@Param
- @Delete(“delete from user where id = #{uid}”)
int deleteUser(@Param(“uid”) int id);
- @Delete(“delete from user where id = #{uid}”)
-
-
-
②在Mybatis核心配置文件绑定接口
-
③测试
-
注意
- ①要确保实体类属性和数据库字段对应
- ②使用注解开发就不用mapper.xml映射文件
- ③映射文件和注解协同使用效率高
Lombok插件
-
功能:通过注解,在编译时自动为POJO生成构造器,setter/getter,toString,equals等方法
-
使用步骤
-
①在IDEA中安装Lombok插件
-
②引入Maven依赖
org.projectlombok lombok 1.18.10 -
③在POJO类中加注解
@Data
//有参构造
@AllArgsConstructor
@NoArgsConstructor
public class User {//当数据库表中的属性和实体类的属性名称不一样时,处理的方法①起别名②使用ResultMap private int id; private String name; private String password;
}
-
-
注解
- @Getter/@Setter,自动生成setter,getter方法
- @ToString,自动生成toString()方法
- @NoArgsConstructor,生成无参构造器
- @AllArgsConstructor,生成有参构造器
- @RequiredArgsConstructor,生成有特定参数构造器
- @Data,生成所有的注解
一对多和多对一处理
数据库:
CREATE TABLE teacher
(
id
INT(10) NOT NULL,
name
VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (id
)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO teacher(id
, name
) VALUES (1, ‘秦老师’);
CREATE TABLE student
(
id
INT(10) NOT NULL,
name
VARCHAR(30) DEFAULT NULL,
tid
INT(10) DEFAULT NULL,
PRIMARY KEY (id
),
KEY fktid
(tid
),
CONSTRAINT fktid
FOREIGN KEY (tid
) REFERENCES teacher
(id
)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO student
(id
, name
, tid
) VALUES (‘1’, ‘小明’, ‘1’);
INSERT INTO student
(id
, name
, tid
) VALUES (‘2’, ‘小红’, ‘1’);
INSERT INTO student
(id
, name
, tid
) VALUES (‘3’, ‘小张’, ‘1’);
INSERT INTO student
(id
, name
, tid
) VALUES (‘4’, ‘小李’, ‘1’);
INSERT INTO student
(id
, name
, tid
) VALUES (‘5’, ‘小王’, ‘1’);
外键约束
constraint 约束名 foreign key references 主表字段
多对一
-
如:多个学生对应一个老师
-
方法一:嵌套Select查询-SQL查询
select * from student select * from teacher where id = #{id} -
方法二:嵌套结果查询-SQL联表查询
select s.id sid, s.name sname, t.name tname, t.id tid from student s, teacher t where s.tid = t.id -
注:由于是多对一,查询的结果唯一,故使用association
一对多
-
如:一个老师对应多个学生
-
方法一:嵌套Select查询-SQL查询
select * from teacher where id = #{tid} select * from student where tid = #{tid} -
方法二:嵌套结果查询-联表查询
select s.id sid, s.name sname, t.name tname, t.id tid from student s, teacher t where s.tid = t.id and t.id = #{tid} -
注:由于是一对多关系,查询结果有多个,是集合,故使用collection
动态SQL
定义:动态地根据属性值来拼接数据库执行的SQL语句(接口对应的映射文件中配置)
if元素
-
作用:若if元素有返回值,自动加入子句
-
e.g.
select * from blog where title = #{title} and author = #{author}- 注:如果例子中的where=1不存在,if标签执行代码报错,故引入了where标签
- test属性为判定条件,真则执行
where元素
-
作用:若包含的标签有返回值便插入where子句,若子句的开头为AND或OR,where元素会将它们去除
-
e.g.
select * from blog title = #{title} and author = #{author}
choose when other元素
-
作用:当不想使用所用条件,而是从多个条件选择一个使用,类似于Java的switch语句
-
e.g.
select * from blog<where> <choose> <when test="title != null"> title = #{title} </when> <when test="author != author"> author = #{author} </when> <otherwise> views = #{views} </otherwise> </choose> </where>
- test属性为判定条件,真则执行
set元素
-
作用:动态在行首插入set关键字,并删除额外逗号
-
e.g.
update blog title = #{title}, author = #{author} where id = #{id}
foreach元素
-
作用:对集合遍历
-
e.g.
select * from blog id = #{id}
sql元素
-
作用:将重复的SQL语句放入SQL标签,增加代码重用性,简化代码,使用引用
-
e.g.
select * from blog
and title = #{title} and author = #{author}<where> <include refid="if-title-author"/> </where>
缓存
一级缓存
- 定义:即,本地缓存,默认情况下开启,SqlSession级别的缓存,无法关闭,与数据库同一会话查询数据会放在本地缓存中
二级缓存
-
定义:即,全局缓存,基于namespace级别的缓存,一个命名空间对应一个缓存
-
使用步骤
-
①在mybatis.xml中开启全局缓存
-
②mapper.xml中配置二级缓存
-
③代码测试
-
注:查出的数据都会被默认放在一级缓存中,只有会话提交或关闭后,一级缓存转到二级缓存
SQL语句
模糊查询
别名查询
分页查询
联表查询
子查询
XMind - Trial Version