MyBatis框架
- 早期叫做 ibatis,代理在 Github
- MyBatis 全称为 MyBatis SQL Mapper Framework for Java(基于Java 的 SQL 映射框架)
MyBatis 提供的功能
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文件在一个目录下-->
? ? ? ? <mapper package="xxx"/>
? ? </mappers>
</configuration>
注意:
主配置文件的路径是以 / 为分隔,但是Mapper文件是以 . 分隔
各标签的先后顺序:
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中添加模板文件
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 相同
参数传递
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();
|