MyBatis框架
- 早期叫做 ibatis,代理在 Github
- MyBatis 全称为 MyBatis SQL Mapper Framework for Java(基于Java 的 SQL 映射框架)
MyBatis 提供的功能
-
提供了创建Connection,Statement,ResultSet等对象的能力,不需要开发人员重复创建
-
提供了执行 SQL 语句的功能
-
提供了循环 SQL,将结果转换为List对象的能力,不再需要开发人员进行迭代
-
提供了关闭资源的能力
MyBatis 的使用
XXXMapper.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="name">
<!--parameterType可以是简单类型、引用类型、Map类型-->
<!--resultType可以是简单类型、引用类型、Map类型-->
<select id="" parameterType="" resultType=""></select>
<!--模糊查询-->
<select id="" parameterType="" resultType="">
select * from table where id like '%' #{id} '%';
<!--'%'和#{}中的空格不能省去,相当于加号,拼接作用-->
</select>
</mapper>
文件解读
- 1.指定的约束文件
<?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 接口的全限定名称(包名 + 类名)
- resultType 应该使用 domian 中的类全限定名称
mybatis.xml 主配置文件(用于连接数据库,放于src目录下)
<?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="db.properties"/><!--加载配置文件-->
<!--
设置与数据库交互环境,例如二级缓存
在实际开发中,基本没用,因为优化效率太低
-->
<settings>
<setting name="cacheEnabled" value="true"/><!--二级缓存-->
<setting name="lazyLoadingEnabled" value="true"/><!--延迟加载-->
<setting name="logImpl" value="STDOUT_LOGGING"/><!--开启日志-->
</settings>
<!--为domain起别名-->
<typeAliases>
<!--方式1-->
<typeAlias type="全路径名称" alias="别名"/>
<!--方式2-->
<!--为一个包下所有domain起好了别名,别名为类名且不区分大小写-->
<package name="包路径名">
</typeAliases>
<!--环境配置-->
<environments default="development"> <!-- default必须与下列某一个id相同,表示当前使用的配置信息-->
<environment id="development"> <!-- id为配置名称,可以随便取-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/framework?useSSL=false&serverTimezone=UTC"/>
<!-- MySQL是8.0以上的版本,driver 和 url 的value 和以前不同,& 等同于 &符号-->
<property name="username" value="root"/>
<property name="password" value="feifei123"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--适用于xml文件和dao文件不在一个目录下-->
<mapper resource="xxx.Xxx.xml"/>
<!--适用于xml文件和dao文件在一个目录下-->
<package name="xxx"/>
</mappers>
</configuration>
各标签的先后顺序:
properties,settings,typeAliases,typeHandlers,objectFactory,objectWrapperFactory,
reflectorFactory,plugins,environments,databaseIdProvider,mappers
属性配置文件
- 把数据库连接信息单独放置在一个文件中,和主配置文件分开
格式key=value
key和=和value之间不可用有空格隔开
key一般使用 . 做多级目录,例:java.driver
利用<properties resource=" ">在主配置文件中指定相关的配置文件
而在主配置文件中只用使用 ${key} 来获取相关的配置信息即可
关于transactionManager : 负责MyBatis的事物提交
type 的两种类型
- JDBC : 表示MyBatis底层调用JDBC的Connection对象进行commit 和 rollback
- MANAGED : 把MyBatis事物处理委托给其他容器(可以是一个服务器,也可以是一个框架(Spring框架))
关于dataSource :表示数据源
type的两种类型
- POOLED : 使用连接池
- UPOOLED : 不使用连接池
- JNDI:java命名和目录服务(类似Windows注册表)
由于XXXMapper文件与 dao 文件一同放在了 java 文件夹下,而不在resources 文件夹下,Maven在进行编译时是会自动跳过java文件夹下的资源文件的,因此我们需要手动的进行调整,让Maven将java文件夹下的资源文件也打包如target/classes中
解决方法 在pom.xml 中加入如下代码:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
MyBatis 使用方法
public static void main(String[] args) throws Exception{
InputStream in = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
SqlSession sqlSession = factory.openSession();
String sqlId = "dao.StudentDao.selectAll";
List<Student> students = sqlSession.selectList(sqlId);
students.forEach(student -> System.out.println(student));
sqlSession.close();
}
代码解读:
Resources: 负责读取主配置文件
Inputstream in = Resources.getResourceAsstrean ( "mybatis.xml");
SqlSessionFactoryBuilder :创建SqlSessionFactory对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder (); //创建sqlsessionFactory对象
SqlSessionFactory factory = builder. build(in) ;
SqlSessionFactory :重量级对象,程序创建该对象耗时比较长,使用资源比较多。在整个项目中,有一个就够用了。(单例模式)
SqlSession sqlSession = factory.openSession() ;
openSession()方法说明:
- openSession() :无参数的,获取是非自动提交事务的sqlsession对象
- openSession (boolean): openSession (true)获取自动提交事务的sqlsession.
SqlSession :
SqlSession接口∶定义了操作数据的方法例如selectone(),selectList() ,insert () , update ()
注意:SqlSession 对象不是线程安全的,因此执行sql语句之前,和使用之后要分别开启和关闭保证其线程安全性。
Mybatis 默认手动提交事务
sqlSession.commit();
在IDEA中添加模板文件
-
选中 File --> Settings --> Editor --> File and Code Templates在其中添加一个文件并命名
MyBatis 动态代理
-
MyBatis 中为我们提供了一套动态代理机制
public static void main(String[] args){
SqlSession sqlSession = MyBatis.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = new Student("024","花木兰",22,"女");
int num = studentDao.insertStudent(student);
sqlSession.commit();
System.out.println("影响行数:"+num);
}
sqlSession.getMapper(StudentDao.class) 通过反射机制获取到StudentDao接口的动态代理类
而在 studentDao.insertStudent(student) 直接使用动态代理接口的方法即可
方法的名字应该与 XXXMapper.xml 文件中的某个 id 相同
参数传递
-
parameterType:传入SQL语句的数据类型因为 MyBatis 具有反射机制,能够识别出数据类型,因此开发中一般不写
MyBatis 四种传值方式
使用@Param传值
接口方法:
List<Student> select(@Param("myid") String id)
sql 语句:
select * from table where id = #{myid};
不推荐使用,参数多时,一个一个命名困难
使用对象传值
select * from table where id = #{id} and name = #{name};
推荐使用,但是{ }中的名字必须是 domain 对象的属性名
按位置传值
按接口中的参数列表中参数的位置进行传输
select * from table where id = #{arg0} and name = #{arg1}
不推荐使用,可读性低,难以维护
Map传值
接口方法:
List<Student> select(Map<String,Object> map)
sql语句:
select * from table where id = #{id} and name = #{name};
推荐使用,但是{ }中的名字必须是 Map 中已有的 key
缺点:光看接口方法难以看出map中有几个参数,参数类型又是什么,并且保证key的正确性
# 和 $ 的区别
- # 相当于 sql语句中的 ?,使用的是PrepareStatement对象,可以防止sql注入
- $ 使用的是字符串拼接,一般用于替换列名或表名(即便如此也有可能被注入)
例如:select * from table order by ${colName};
select * from ${tableName};
简单类型 (String + 基本数据类型) 可以直接写简写,不需要包名,不区分大小写
Map类型无法迭代,可以先使用 map.keySet() 获取 map集合的关键字集合,再对关键字集合进行迭代获取 value
当使用分组查询的时候,只能使用map来封装查询结果,而不能用domain,因为domain没有count属性
resultMap
- 用于指定列名与java对象的属性对应的关系(支持复用)
使用情况:
- 自定义赋值给某个属性时
- SQL列名与对象属性名不相同时
<resultMap id="mapName" type="java全限定名">
<id column="id" property="id"/> <!--主键列-->
<result column="age" property="peopleAge"/> <!--非主键列-->
</resultMap>
<select id="selectCount" resultMap="mapName">
select * from student;
</select>
PS:在sql 语句中用 as 来调整列名,也可以解决SQL列名与对象属性名不相同的问题
模糊查询
方法一
select * from table where name like #{name};
需要在接口方法中传入一个name的字符串,推荐使用
方法二
select * from table where name like "%" #{name} "%";
还是需要在接口方法中传入一个name的字符串,只是内容不同
动态 SQL
sql 的内容是变化的,可以根据条件不同获取到不同的sql语句
主要是where部分的变化
使用的是MyBatis提供的标签,<if> <where> <foreach>
<if> 标签
<if test="name != null and name != '' ">
and name = #{name}
</if>
当一个条件满足时,但是前面又没有其他条件时,多出来的and会导致sql语句报错(where and name = #{name})
因此我们会在where后面加入一个无关紧要的条件例如 1=1 这样来改善代码
where 1=1 and name = #{name};
这样代码自然就不会报错了
<where> 标签
<where>
<if test="name != null and name != '' ">
and name = #{name}
</if>
</where>
where 会将第一个多余的无效字符去除<foreach>标签
<froeach collection="" item="" open="" close="" separator="">
</foreach>
collection:表示接口方法中参数类型,如果是数组用array,如果是List用list
item:是自定义的集合成员变量(如果成员变量是对象,则用#{对象.属性}即可)
open:循环开始字符
close:循环结束字符
separator:集合成员之间的分隔符
open,close,separator 可以直接写在sql语句内,因此可以省去不写
代码片段
定义片段
<sql id="sql_1">
select * from table_1
</sql>
调用片段
<include refid="sql_1"> where id=#{id}
不推荐使用,可读性低
PageHelper(不属于MyBatis框架,国内作者创作)
maven
<dependency>
<groupId>com.github.pagehelper</groupId>
<artiactId>pagehelper</artiactId>
<version>5.1.10</version>
</dependency>
主配置文件
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>
在进行查询前使用
PageHelper.startPage(页数,行数);
List<Student> students = dao.selectAll();