前言
ORM是持久化映射框架,但是MyBatis的本质并不是ORM框架。
如何使用MyBatis执行数据库语句
依赖导入
首先如果是Maven工程,则导入JDBC的依赖以及MyBaits的核心依赖。
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
这里顺手导入了单元测试的依赖,方便我们运行测试效果。
如果是普通的Java工程,则使用Jar包也是可以的,对于SSM框架的学习还是只建议使用Maven工程去学习。
配置文件
MyBatis需要核心配置文件,最简单的核心配置文件就是三大部分:
事务管理器
<transactionManager type="JDBC"/>
数据源
<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>
上面两个部分都是在环境标签元素里声明定义的
<environments default="development">
<environment id="development">
<!-- 包含着事务管理和数据源 -->
事务管理...
数据源...
</environment>
</environments>
映射文件管理
<mappers>
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
上面只是单个Mapper文件的管理,可以改为package,也就是包级别的管理,不论是别名还是映射文件等等,都可以使用包级别的管理,如果使用了包级别的管理,则MyBatis会自动起别名,别名是类名的驼峰。
上面三大部分以及父标签都是在configuration标签中,该标签英译是配置。
<configuration>
环境配置...
事务管理...
数据源...
映射文件复数
映射文件单数...
</configuration>
定义Mapper映射文件
该文件第一行是一个mapper标签,该标签有一个属性就是namespace,该属性代表唯一命名空间。
<mapper
namespace="com.atguigu.mybatis.
mappers.UserMapper">
</mapper>
该标签的命名空间应该和我们定义的Mapper接口的路径相同,这样方便后续的整合,也比较规范。
在mapper标签里,我们可以定义基本的增删改查标签
<insert id="insertUser">
insert into t_user values(null,'admin','12456',23,'男','12345@qq.com')
</insert>
<update id="updateUser">
update t_user set username = 'root',password = '123' where id = 3
</update>
<delete id="deleteUser">
delete from t_user where id = 3
</delete>
<!-- 这里的resultType是别名类型,如果不是别名则要写全类名才行 -->
<select id="getUserById" resultType="user">
select * from t_user where id = 1;
</select>
<select id="getAllUser" resultType="user">
select * from t_user
</select>
上面的MapperXML文件并没有什么特殊的,就是唯一命名空间+SQL语句标签的id,让MyBatis来调用。
定义Mapper接口
该接口上面提到了,应该和MapperXML文件的唯一命名空间相同,也就是全类名等于XML文件的唯一命名空间,而该XML文件里定义的SQL语句标签的id则应该和该接口里的方法名相同。
public interface UserMapper {
int insertUser();
void updateUser();
void deleteUser();
User getUserById();
List<User>getAllUser();
}
上面是个接口,方法名要和MapperXML文件里的SQL标签id的命名一样。
MyBatis的测试调用准备
经过上面的核心配置文件、MapperXML文件、Mapper接口的配置后,我们可以进行测试了。
在Maven工程的test目录下创建一个测试类,该类使用单元测试直接,此处的方法需要加载MyBatis核心配置文件(获取核心配置文件的输入流),然后通过MyBatis的SqlSessionFactoryBuilder来创建对象创建工厂类,然后再通过该类来获取实际的SqlSession对象,我们操作MyBatis的核心就是SqlSession类。
SqlSessionFactoryBuilder
SqlSessionFactory
SqlSession(构造器可传入布尔值)
sqlSession.insert()...selectOne()...
sqlSession.getMapper(Class.class)...
sqlSession.commit()...如果构造器是true,此代码则无须声明
sqlSession.close()...
上面的流程是固定的,所以建议写一个工具类来稳定获取SqlSession,前面两个类都是我们获取SqlSeesion的一个流程而已。
下面演示工具类。
public class SqlSessionUtil {
public static SqlSession getSqlSession() {
SqlSession sqlSession = null;
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
sqlSession = sqlSessionFactory.openSession(true);
} catch (IOException ioException) {
ioException.printStackTrace();
}
return sqlSession;
}//咱们就别写必然的close了,因为要用,而不是获取一个熄火的sqlSession
}
MyBatis的执行测试
经过上面的流程,我们获取了MyBatis的核心操作对象:SqlSession对象。
我们通过SqlSession来调用我们在Mapper接口和Mapper配置文件声明的SQL语句,有两种方式:
第一种:使用原生的方法操作
int result =
sqlSession.insert(MapperXML命名空间+SQL标签的id);
第二种:使用代理类产生接口实现类操作
UserMapper mapper = sqlSession.getMapper(Mapper接口类的class对象);
var mapper = sqlSession.getMapper(Mapper接口类的class对象);
在实际的应用中,我们一般都使用的是第二种,而且后续还会有使用注解来实现操作,所以肯定是首选第二种方式,不过第二种方式的源码其实底层实现就是使用的第一种方式。
额外扩展:添加日志功能介绍
日志功能有很多框架,这里我们用的是log4j,日志的意义就是输出一些信息,信息中会有实际执行的sql语句,以及参数的信息。
添加流程:增加日志功能的依赖
我们现在pom文件里添加log4j的依赖:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
如果是java工程,则自己去下载其jar包,然后添加jar包依赖就行了,不过比较麻烦和可能有不显示的bug。
添加流程:增加日志功能的配置文件
该文件的文件名也是固定的,叫log4j.xml,该文件的内容也是固定的,我们先复制粘贴用着就行了,就别去纠结内容了。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS}
%m (%F:%L) \n" />
</layout>
</appender>
<logger name="java.sql">
<level value="debug" />
</logger>
<logger name="org.apache.ibatis"><level value="info" />
</logger>
<root>
<level value="debug" />
<appender-ref ref="STDOUT" />
</root>
</log4j:configuration>
日志功能添加的总结
这个添加日志功能的流程确实简单,也就两步,但是核心配置文件肯定是不容易看懂的,不过在初学者阶段,就不要纠结太多固定并且常用的内容了,自己知道有这回事情就行了,日志功能在MyBatis的执行测试里充当着额外信息的提供者,是非常重要和必要的功能扩展,只有拥有了日志信息,我们在后续的关系关联查询中才能看出来不同设置带来不同的流程效果,因为可能它们的运行结果是相同的,但是流程是可能不一样并且差距很大的。
MyBatis的标签元素使用记录
为类声明别名
我们如果没有声明别名,则每次都需要使用全类名+id来定位,这样即麻烦又冗余,所以我们可以在核心配置文件中进行类型声明。
如果是接口类的别名,则在核心配置文件中增加标签元素typeAlias标签元素。
<!-- 要是不指定alias则就是默认是类名,不区分大小写 -->
<typeAlias type="com.atguigu.mybatis.pojo.User" alias="User"></typeAlias>
有了该别名,我们在XML文件中将resultType或reusltMap那些要用到java类型的地方就可以替换成该声明的别名,十分的方便和实用。
如果是多个类都要起别名,并且这些类都在pojo包下等等情况,我们则可以用另一种形式来指定别名:
<!-- 该包下的全部类都将拥有默认的别名,不区分大小写 -->
<package name="com.atguigu.mybatis.pojo"/>
数据源的优化配置
这里意思就是,我们在dataSource中的property标签元素的优化,是这样的首先前面的name标签属性是不变的,value的赋值改为:${key}的形式,来赋值,该形式可以用properties文件,没错,在jdbc也这么使用过的。
但是在使用该语法前,需要在核心配置文件中添加properties元素标签,在resource属性中指定properties文件的路径,一般我们都用相对路径就行了,该文件普遍都和核心配置文件以及日志配置文件放在resources目录里。
<properties resource="jdbc.properties"/>
这里有一个标签顺序需要注意。properties 声明在environments和typeAliases前面,所以typeAliases是在properties 后面的,这里只是将三个标签元素,如果有其他标签元素,则顺序另谈,经过上面的标签元素设置,我们才可以去value值进行${value}形式的赋值。
jdbc文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
jdbc.username=root
jdbc.password=password
修改语法的dataSource子元素
<!-- 语法:${key}
其实和Map集合差不多 -->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
Mappers文件配置和一些设置
我们如果是单个配置的话,就是在Mappers里定义一个mapper,然后mapper的resource指定Mapper文件的路径,如果有很多个Mapper文件都需要加载管理,则这种写法是行不通的。
单个Mapper文件引入的写法
<mapper resource="mappers/UserMapper.xml"/>
通过包级进行引入加载管理
<mappers>
<!--
使用包的方式引入映射文件,需要必须满足两个条件:
1、mapper接口和映射文件所在的包必须一致
2、mapper接口的名字和映射文件的名字必须一致
资源文件肯定创建不了包(package)因为不是java级的嘛
不过包在磁盘上的本质就是一个目录,所以我们这里创建目录即可
包语法:com.atguigu...
目录语法:com/atguigu...
创建完毕后,将mapper文件移动到该目录里,往后都是这样写的,mappers文件夹就可以删除掉了
-->
<package name="com.atguigu.mybatis.mappers"/>
</mappers>
java是存放我们的java程序源码的,resources是存放我们的配置文件的,它们编译后都放在了同一个文件里,在Maven中,tagert表示编译目录,这里面存放了类编译和Jar包依赖等等,我们打开tagert的这个目录来验证它们编译后被放在了一起的理论。
所以这也是上面使用包引入的必须条件。
在IDEA里创建文件模板
我们每次创建核心配置文件或者Mapper文件时,这些文件的基本必要内容都是我们需要去官方或者其他网站上获取的,这样很麻烦,我们可以在IDEA里创建文件模板来进行保存,每次使用直接创建该文件模板的文件即可。
流程演示
上面的name只是模板的名字,我们在新建该模板文件时的文件名依然是要自己指定的,java是文件后缀,我们这里要改成xml
文件代码模板记录
mybatis-config.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>
<properties resource="jdbc.properties"/>
<typeAliases>
<package name=""/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<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>
</environment>
</environments>
<mappers>
<package name=""/>
</mappers>
</configuration>
??mapper.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 namespace="">
</mapper>
上面的两个文件其实就是文件必备约定等等设置和官方定义的必要根标签元素。
MyBatis获取参数的五种情况
MyBatis通过#{}或者${}来获取参数,两者区别不大,只是${}需要手动添加单引号,不过在某些场景,只能使用${},用的最多的还是#{},#{}表示的是占位符,${}则直接是直接量或者引用的值。
第一种
该情况是如果SQL语句只设置了一个字面量,那么此时不论是#{}还是${}的名称都随意设置
select * from t_user where username = ${'abc'}
第二种
如果有多个字面量,则需要使用MyBatis提供的两种参数获取方式,第一种是arg0、arg1…的方式来获取,根据声明顺序排序,第二种是param1、param2…的方式来获取,该方式和第一种没有区别,只是MyBatis分两种形式所保存的Map集合。
<!-- select * from t_user where username = #{arg0} and password = #{arg1} -->
select * from t_user where username = #{param1} and password = #{param2}
第三种
第三种则是自定义一个Map数组,然后把这个Map数组作为参数传递进去,此时我们就可以根据自定义的Map数组的key来取value的值。
Map<String,Object>map = new HashMap();
map.put("username","admin");
map.put("password","123456");
select * from t_user where username = #{username} and password = #{password}
这种只是自定义了key而已。
第四种
第四种则是使用实体对象,就是把类对象作为参数,获取参数的方式就是获取类的属性,类属性相当于成员变量+setter+getter的JavaBean规范。
User user =
new User(null,"root","123456",33,"女","123@qq.com");
insert into t_user values(null,#{username},#{password},#{age},#{gender},#{email})
上面的#{}里的变量应该是POJO里定义的属性。
第五种
第五种使用了注解,该注解为@Param()。该注解的本质就是,当MyBatis将我们传入的参数保存时不再以arg或param的形式保存,而是以我们注解里声明的名称作为key来保存value的值,也就是说还是保存在了Map里,但是key是我们定义注解的值。
User checkLoginByParam(@Param("username") String username,@Param("password") String password);
这种方法不需要写arg或param这种可读性差的字面量,也不用手动做map放进去,而无须必须创建一个对象去赋值。
第五种是最常用和实用的方式了。
//命名参数,MyBatis封装参数时,根据我们注解的命名进行封装
User admin = mapper.checkLoginByParam("admin", "123456");
p26