什么是mybatis?
- 是一款优秀的持久层框架,用于简化JDBC开发。
什么是持久层?
- javaee有三层架构:表现层,业务层,持久层
- 其中,持久层就是负责将数据保存到数据库的那一层代码。
什么是框架?
- 框架是一个半成品软件,是一套可重用的、通用的,软件基础代码模型。
- 在框架的基础上构建软件编写更加高效、规范、通用、可拓展。
1.快速入门
官网入门教程:https://mybatis.org/mybatis-3/zh/getting-started.html
- 创建一个数据库的表
- 创建模块,导入坐标(mysql,junit,logback,mabatis)
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!-- logback -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
</dependency>
<!-- mybatis 核心 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- junit 测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
- 编写mybatis的xml核心配置文件
直接用下面这里的配置文件,其中有部分需要修改
如果是5.几的mysql版本,就把driver属性那的cj去掉,8.几的版本就加上
url,username,password都按照jdbc连接数据库的方式填自己的
mappers是寻找持久化映射文件,其实就是找sql语句的操作文件,在同一目录下就直接写文件名
<?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>
<!--加上这个,我们就是定位了sql里面返回类型类所在的包,到时候直接写类名,就不用包名+类名了->
<typeAliases>
<package name="com.it"/>
</typeAliases>
<!--环境配置,连接的数据库,这里使用的是MySQL,可以配置多个enviroment,通过default属性可以切换不同的enviroment-->
<environments default="mysql">
<environment id="mysql">
<!--指定事务管理的类型,这里简单使用Java的JDBC的提交和回滚设置-->
<transactionManager type="JDBC"></transactionManager>
<!--dataSource 指连接源配置,POOLED是JDBC连接对象的数据源连接池的实现-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/db01"></property>
<property name="username" value="root"></property>
<property name="password" value="hsp"></property>
</dataSource>
</environment>
</environments>
<mappers> <!--这是告诉Mybatis区哪找持久化类的映射文件,对于在src下的文件直接写文件名, 如果在某包下,则要写明路径,如:com/mybatistest/config/User.xml-->
<mapper resource="UserMapper.xml"></mapper>
</mappers>
</configuration>
- 写持久化映射文件(sql语句文件)
这里注释比较乱,解释一下
namespace,就是包的功能,里面写具体的sql语句
sql语句用对应的子节点包起来,属性 id是这个语句的唯一标识符,result是返回类型(一般返回到一个类里面,这个类有他的对应的列名)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
namespace:名称空间,作用和包的作用一样,用sql的时候在前面加上他
-->
<mapper namespace="test">
<!-- id是这个语句的唯一标识,resultType是返回类型-->
<select id="selectAll" resultType="com.it.User">
<!-- 这里写sql语句-->
select * from class;
</select>
</mapper>
- 创建对应的返回的类
//主要是以下内容,再加上构造器和重写toString方法
private Integer id;
private String ename;
- 在主文件中,执行
分为几步:
(1)通过输入流,把mybatis文件输入到实例化SqlSessionFactor这个工厂,mybatis文件里记录了所有信息,包括连接数据库、以及sql执行文件的信息。
(2)通过这个工厂,实例化一个SqlSession对象,也就是执行sql语句的对象
(3)直接执行,因为我们已经导入了那个sql语句文件,所以这里相当于直接选择执行那个语句,通过语句的id,也就是唯一标识符来指定
(4)打印然后关闭sqlSession
//加载mybatis的配置文件,获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//由工厂获取SqlSession对象,用它执行sql语句
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行sql语句
List<User> users = sqlSession.selectList("test.selectAll");
System.out.println(users);
sqlSession.close();
2.mapper代理方式简化开发
mapper主要解决的是两个问题:
(1)我们在文件中写这行代码时
List<User> users = sqlSession.selectList("test.selectAll");
参数是字符串,这样子很容易打错,而且没有自动补全
(2)在mybatis配置文件里面的加载sql映射文件的时候,也就是下面这行
<mapper resource="UserMapper.xml"></mapper>
如果有好几个映射文件,那要写很多行
解决方式:
(1)如果能把test.selectAll这个id变成一个方法,这样就可以自动补全了,具体操作如下:
①新建一个接口,然后,名字和那个sql映射文件同名,然后放到一个目录下。如何放到一个目录下呢?首先在java下建包,把接口放进去。然后再resources下建一个同名的Directory(各层用/分割而不是用点),把sql映射文件放进去。这样就在一起了。如下图
这里注意,这个接口是不用实现的,只需要在映射文件的xml文件里,把语句的namespace改成全名,com.itheima.mapper.UserMapper就行了,这样这俩文件才能关联起来。
②定义接口里面的方法,要和sql映射文件里的sql语句的id名字相同,然后返回类型一定要是应该的返回类型。
List<User> selectAll();
③这样子就配置好了,然后使用的时候
首先创建对应的mapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
然后直接执行,这样就有了提示
List<User> users = userMapper.selectAll();
(2)解决第二个问题:
既然我们的sql映射文件未来都在同一个包下,这个包里也没别的配置文件,那我们直接用扫描包的形式来加载sql映射文件即可
//原来是他
<mapper resource="UserMapper.xml"></mapper>
//直接改成他
<package name="com.itheima"/>
3.mybatisx
这是一个非常好用的插件,可以在sql映射文件和对应的mapper接口之间跳转,并且还可以写mapper接口他会自动生成sql映射文件对应的结构。
4.增删改查操作流程
编写接口方法
编写sql语句
执行
5.传参数:
在接口里面直接接收
在sql映射文件里用
#{}(prepareStatement,这个会替换成?,防止sql注入)
或者
${}(Statement,会直接带进去,有注入问题)
多参数,要特殊处理,三种方法如下
①需要加注解如下
Integer insertOne(@Param("id")int id, @Param("ename")String ename);
<insert id="insertOne">
insert into class values(#{id},#{ename});
</insert>
②几个参数属于同一个对象,可以直接传对象
这里需要占位符里的名称和对象里的属性名称一样,不然找不到
③map键值对的方式,直接传map,然后占位符写键值
6.特殊字符:
对于特殊字符,可以转义或者CDATA区,在这个范围内的都是纯文本,不是关键字
比如小于号。输入CD,idea就会提示
<![CDATA[
]]>
7.动态sql
动态查询
动态sql是mybatis的强大特性之一,普通的sql语句用 if 判断很痛苦
<if test="条件判断">
执行语句
</if>
有一个BUG :多个if判断,每一个if里面的语句结构不同,第一个是正常的,第二个以后的语句都会有连接符and,这样如果第一个判断错误,会直接就是and,语法错误
解决方式:在开头加一个恒等式1=1
或者用mybatis提供的where,他会自己动态的给你调整语法,牛皮的很。他会检测你是不是第一个,自动删除你的and,还有一些其他的问题也会调
<where>
</where>
单条件动态查询
choose(when,otherwise),相当于java中的switch
应用于:选择查询这个人的名字?还是身份证?
BUG是:如果用户一个都不选,会报错
解决:下面有个otherwise,就是defualt
8.主键返回
我们添加了一条记录以后,添加的时候不写主键,它会自动增1。但是我们有时候需要获取这条记录的主键
这时候只需要在insert id=“xxx” 后边加 useGeneratedKeys=“true” keyProperty=“id”
这样我们添加完了以后,就可以直接去对象里面看id(这个对象是,我们传入的对象,就是我们添加多个对象的时候,第二种方法,把参数封装到对象里)
9.批量删除
基本语句:
delete from table where id in (1,2)
所以,我们需要的参数是一个数组
有了数组,我们不知道究竟这个数组里有几个元素,所以需要循环遍历数组
用到的是foreach collectionn,代码如下
<delete id="deletes">
delete from class where id
in(
<foreach collection="array" item="id" separator=",">
#{id}
</foreach>)
</delete>
在mybatis中,数组被封装成了map,有对应的键值和value,其中键值叫做array,然后要获取的值是id。因为循环中的数应该用逗号分隔,不然语法不对,所以加上separator,作用是加分隔符。
10.注解开发
在mapper的语句旁边,直接写
@select("select * from class");
就可以,一般简单的可以这样,但是不好维护,复杂的还是要用xml