什么是MyBatis?
MyBatis是持久层框架,也就是javaweb中的DAO层。用来简化使用者对数据库的一系列操作,MyBatis相当于增强版的JDBC,我们不需要关注数据库如何连接,如何查询等操作,只需要将我们需要的SQL语句写到sqlmapper映射文件中,并调用接口即可。大大简化了开发的繁琐任务。
MyBatis的配置
在默认已经学会使用Maven工具的前提下,我们可以将MyBatis的依赖和数据库连接的依赖加入到Maven的pom.xml文件中。
----------MyBatis的jar包依赖----------
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
----------数据库连接的jar包依赖----------
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
加入依赖后,我们在Maven项目下的src/main/resources目录下,创建一个mybatis.xml文件,里面用来存放我们连接数据库的环境配置,在这里我们可以参考MyBatis的官方文档,里面有详细的环境配置信息。
在下面的代码中,我使用了配置文件properties来引入MySQL的配置信息。该配置文件也放到rc/main/resources目录下。
properties数据库连接配置文件↓
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm
jdbc.user=root
jdbc.password=123456
配置信息中的dtd来对我们MyBatis配置信息进行规定。不符合规定语法会报错。
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
在configuration双标签内部使用properties单标签对配置文件进行引入,使用${key}可以获取key对应的value。
<properties resource="property.properties"/>
为了能让我们看清楚MyBatis框架的具体操作过程,我们可以加入日志文件,对执行sql语句的过程进行记录。
<settings>//日志配置信息
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
typeAlies标签可以为我们的sqlmapper文件中的resultType起一个别名。让我们不需要为sql语句的返回值每次都写入返回类型的全限定名称。
typeAlias的使用有两种方法:
<typeAliases>
<!--该种方法会将该包下的所有类直接作为返回值类型-->
<package name="com.right.pojo"/>
<!--该方法要指定到具体的一个类,为该类起一个别名-->
<!-- <typeAlias type="com.right.pojo.MyStudent" alias="MyStudent"/>-->
</typeAliases>
两种方法只能选择一种使用,推荐使用第一种方法。
在environments 标签内我们可以配置多个数据库信息,并使用default对要使用的数据库进行指定。
transactionManager该标签表示我们处理事务的方式,默认采用JDBC事务的处理方式,我们还可指定用Spring等其他方式处理事务。
<transactionManager type="JDBC"/>
dataSource表示数据源处理方式,默认使用线程池进行处理,如果不使用线程池的话,使用UNPOOLED的话,在并发量比较大的情况下可能会影响sql操作的效率。
<dataSource type="POOLED"></dataSource>
mapper文件中指定了我们的MyBatis去何处寻找我们的sqlmapper文件,mapper配置方式也有两种:
<mappers>
<!--告诉 mybatis 要执行的 sql 语句的位置-->
<!-- <mapper resource="com/right/dao/StudentDao.xml"/>-->
<!--该包下的所有sqlmapper.xml-->
<package name="com.right.dao"/>
</mappers>
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>
<properties resource="property.properties"/>
<!--日志配置信息-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package name="com.right.pojo"/>
<!-- <typeAlias type="com.right.pojo.MyStudent" alias="MyStudent"/>-->
</typeAliases>
<!--配置 mybatis 环境-->
<environments default="mysql">
<!--id:数据源的名称-->
<environment id="mysql">
<!--配置事务类型:使用 JDBC 事务(使用 Connection 的提交和回滚)-->
<transactionManager type="JDBC"/>
<!--数据源 dataSource:创建数据库 Connection 对象
type: POOLED 使用数据库的连接池
-->
<dataSource type="POOLED">
<!--连接数据库的四个要素-->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--告诉 mybatis 要执行的 sql 语句的位置-->
<!-- <mapper resource="com/right/dao/StudentDao.xml"/>-->
<package name="com.right.dao"/>
</mappers>
</configuration>
sqlmapper配置
在配置sqlmapper之前我们先创建一个接口,接口中放置了我们的sql方法。
之后再在接口同级目录下配置sqlmapper文件,该文件名要与接口名一样,后面反射需要用到该处细节。
namespace命名空间必须有值,且该值必须唯一,我们需要使用该值来找到sqlmapper。
sql标签内的id要与我们接口中的方法名称一致,后期我们测试时可以通过调用接口内部的方法来对应sqlmapper中的id找到对应的sql语句,实现对数据库的操作。
<?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">
<!--
namespace:必须有值,自定义的唯一字符串
推荐使用:dao 接口的全限定名称
-->
<mapper namespace="com.right.dao.StudentDao">
<!--
<select>: 查询数据, 标签中必须是 select 语句
id: sql 语句的自定义名称,推荐使用 dao 接口中方法名称,
使用名称表示要执行的 sql 语句
resultType: 查询语句的返回结果数据类型,使用全限定类名,如果起了别名可以用别名代替
-->
<select id="selectStudents" resultType="com.right.pojo.Student">
<!--要执行的 sql 语句-->
select * from student
</select>
</mapper>
具体测试
配置完MyBatis.xml和sqlmapper文件后,我们需要进行测试。
测试需要获取sqlSession对象,该对象提供了测试方法,想要获取该对象则需要先获取sqlSessionFactory对象,sqlSessionFactory对象是一个重量级对象,在整个数据库操作过程中,我们只需要创建一个即可。
我们可以将获取sqlSession对象的代码封装到一个工具类中。
package com.right.utils;
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;
public class MybatisUtil {
private static SqlSessionFactory factory =null;
static{
String config = "mybatis.xml";
try {
InputStream in = Resources.getResourceAsStream(config);//获取MyBatis配置信息,放入输入流中
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
factory = builder.build(in);//将输入流读取到SqlSessionFactoryBulider对象中,创建一个sqlSessionFactory对象
} catch (IOException e) {
e.printStackTrace();
}
}
//通过SqlSessionFactory对象的openSession方法创建SqlSession对象
public static SqlSession getSqlSession(){
if (factory != null) {//确保只创建一个SqlSessionFactory对象
SqlSession sqlSession = factory.openSession();
return sqlSession;
}
return null;
}
}
我们先通过工具类获取到SqlSession对象。
想要访问到sqlmapper文件,我们首先需要获取接口对象。该对象的调用通过反射完成,该反射可以让我们获取接口的全类名。因此为了保证程序的正常运行,接口的全类名和sqlmapper中的namespace值要相同。
调用接口的方法,即可访问到sqlmapper中对应的方法。
当我们完成数据库操作后要关闭SqlSession。
@Test
public void selectStudentsTest(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> students = studentDao.selectStudents();
sqlSession.close();
students.forEach(System.out::println);
}
当数据库列名和对象属性名不一致时
在sqlmapper文件中,当数据库列名和对象属性名不一致时,我们可以使用resultMap标签为其名称进行对应。其中id标签代表主键,result为普通列名。
将查询结果返回值返回到resultMap即可完成数据库列名和对象属性名的转换。
我们也可直接使用数据库语法as起别名,但是不提倡。
<resultMap id="selectStudents" type="com.right.pojo.MyStudent">
<id column="id" property="stuId"/>
<result column="name" property="stuName"/>
<result column="email" property="stuEmail"/>
<result column="age" property="stuAge"/>
</resultMap>
<select id="selectStudentsByMapper" resultMap="selectStudents">
select id,name,email,age from student
</select>
动态sql
在sqlmapper文件中,常用的动态sql标签为if
、where
、foreach
if的用法
在test中放置条件,满足条件的if标签内的sql语句会进行拼接。
<if test="" >sql语句 </if>
但是在使用if时,需要在 where 后手工添加 1=1 的子句。因为,若 where 后的所有if条件均为 false,而 where 后若又没有 1=1 子句,则 SQL 中就会只剩下一个空的 where,SQL出错。所以,在 where 后,需要添加永为真子句 1=1,以防止这种情况的发生。但当数据量很大时,会严重影响查询效率。
这时我们就可以使用where标签对if进行包裹。在有查询条件时,可以自动添加上 where 子句;没有查询条件时,不会添加where 子句。
foreach的用法
如果传入的数据是数组,collection则为array,如果传入数据是集合,collection为list
<foreach collection="集合类型" open="开始的字符" close="结束的字符"
item="集合中的成员" separator="集合成员之间的分隔符">
#{item 的值}
</foreach>
sqlmapper中#和$的区别
#代表创建的数据库操作对象为PrepatedStatement类型,该对象编译sql语句方式:先编译sql语句,再将值传入占位符中。可以有效放置sql注入问题,并且效率较高。
$代表创建的数据库操作对象为Statement类型,该对象会将本身的sql语句和要传入的语句进行拼接,可能会造成sql注入问题,并且效率较低。