MyBatis
1、MyBatis简介
1.1、什么是MyBatis
- MyBatis 是一款优秀的持久层框架
- MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的过程
- MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 实体类 【Plain Old Java Objects,普通的 Java对象】映射成数据库中的记录。
- 主要是代替的jdbc,实现快速的开发
- MyBatis官方文档:https://mybatis.org/mybatis-3/zh/getting-started.html
1.2、为什么需要MyBatis
- Mybatis就是帮助程序猿将数据存入数据库中 , 和从数据库中取数据 .
- 传统的jdbc操作 , 有很多重复代码块 .比如 : 数据取出时的封装 , 数据库的建立连接等等… , 通过框架可以减少重复代码,提高开发效率 .
- 所有的事情,不用Mybatis依旧可以做到,只是用了它,所有实现会更加简单!
2、MyBatis第一个程序
2.1、思路流程:搭建环境–>导入Mybatis—>编写代码—>测试
-
搭建实验数据库
`student`CREATE DATABASE `MyBatis`; USER MyBatis; CREATE TABLE `student`( `id` INT(11) UNSIGNED AUTO_INCREMENT, `name` VARCHAR(30) DEFAULT NULL, `age` INT(11) DEFAULT NULL, PRIMARY KEY(`id`) )ENGINE=INNODB DEFAULT CHARSET=utf8; INSERT INTO `student`(`name`,`age`)VALUE('李四','20'),('张三','30'),('王五','40'); SELECT * FROM `student`;
-
导入MyBatis相关 jar 包,Mevan中找https://mvnrepository.com/search?q=Mybatis
<dependencies> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> </dependencies>
-
编写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> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <mapper resource="edu/hunan/dao/UserMapper.xml"/> </mappers> </configuration>
-
-
编写MyBatis工具类
-
查看帮助文档
//工具类 public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory; static { try { String resource = "Mybatis.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } //获取SqlSession连接,可以执行SQL中所有的方法 public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); } }
-
-
创建实体类
//实体类 public class User { private int id; private String name; private int age; 这里省略构造函数,set,get,tostring方法
-
写Mapper接口类
public interface UserDao { List<User> getUserList(); }
-
编写Mapper.xml配置文件
-
namespace 十分重要,不能写错!
<?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对应接口全路径--> <mapper namespace="edu.hunan.dao.UserDao"> <!-- id=对应接口中的方法,resultType=对应实体类--> <select id="getUserList" resultType="edu.hunan.pojo.User"> select * from student </select> </mapper>
-
-
编写测试类
public class UserDaoTest { @Test public void test(){ // 调用工具类的getSqlSession()方法,是可以执行SQL中的所有方法 SqlSession sqlSession = MybatisUtils.getSqlSession(); // 与接口绑定,为了操作接口 UserDao mapper = sqlSession.getMapper(UserDao.class ); //调用接口中对应的方法 List<User> userList = mapper.getUserList(); for (User user : userList) { System.out.println(user); } //关闭资源 sqlSession.close(); } }
2.2、可能出现问题说明:Maven静态资源过滤问题
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
3、CRUD(增删改查)
1、namespace
namespace中的包名要和Dao/mapper接口中的包名一致!
2、select
查询语句
- id:就是对应的namespace中的方法名;
- redultType: Sql语句执行的返回值!
- parameterType: 参数类型!
-
编写接口
//根据id查用户 User getUserid(int id);
-
编写对应的mapper中的Sql语句
<!-- id:就是对应的namespace中的方法名;redultType: Sql语句执行的返回值!parameterType: 参数类型!--> <select id="getUserid" parameterType="int" resultType="edu.hunan.pojo.User"> select * from student where id=#{1} </select>
-
测试
//根据id查用户 @Test public void b(){ SqlSession session = MybatisUtils.getSession(); UserDao mapper = session.getMapper(UserDao.class); User userid = mapper.getUserid(1); System.out.println(userid); session.close(); }
3、Insert
<insert id="getUsername" parameterType="edu.hunan.pojo.User">
insert into student(id,name,age)value(#{id},#{name},#{age})
</insert>
4、Update
<update id="getUpdate" parameterType="edu.hunan.pojo.User">
update student set name=#{name},age=#{age} where id=#{id}
</update>
5、Delect
<delete id="delete" parameterType="int">
delete from student where id=#{id}
</delete>
注意点:
- 增删改查需要提交事务
6、万能Map
-
接口
int getUddate2(Map<String,Object> map);
-
Sql语句
<update id="getUddate2" parameterType="map"> update student set name=#{name} where id=#{id} </update>
-
测试
@Test public void g(){ SqlSession session = MybatisUtils.getSession(); UserDao mapper = session.getMapper(UserDao.class); Map<String, Object> map = new HashMap<String,Object>(); map.put("name","liis"); map.put("id",1); mapper.getUddate2(map); session.commit(); session.close(); }
Map传递参数,直接在sql中取出Key即可! 【parameterType=“map”】
对象传递参数,直接在sql中取对象的属性即可! 【parameterType="User“】
只有一个基本类型的情况下,可以直接在sql中取到!
多个参数用Map,或者注解!
7、模糊查询
-
sql语句
<select id="getlike" resultType="edu.hunan.pojo.User"> select * from student where name like #{name} </select>
-
测试
public void like(){ SqlSession session = MybatisUtils.getSession(); UserDao mapper = session.getMapper(UserDao.class); List<User> getlike = mapper.getlike("%李%");//传递通配符% % for (User user : getlike) { System.out.println(user); } session.commit(); session.close(); }
注意点:Java代码执行的时候,传递通配符% %
4、配置解析
1、核心配置文件
-
核心配置文件
<?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> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="org/mybatis/example/BlogMapper.xml"/> </mappers> </configuration>
-
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下
configuration(配置) properties(属性) settings(设置) typeAliases(类型别名) typeHandlers(类型处理器) objectFactory(对象工厂) plugins(插件) environments(环境配置) environment(环境变量) transactionManager(事务管理器) dataSource(数据源) databaseIdProvider(数据库厂商标识) mappers(映射器)
-
掌握2、3、4和最后一个即可!
2、环境配置
MyBatis 可以配置成适应多中坏境
不过要记住: 尽管可以配置多个坏境,但每个SqlSessionFactory实例只能选择一种环境。
学会使用多套坏境
<!-- 多套环境下只需修改default="xxxx(<environment id="development">)"即可!!-->
<environments default="test">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
3、属性
我们可以通过 properties 属性来实现引用配置文件
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。【db.properties】
实际上就是编写一个db.properties文件,然后在引用文件即可!!
设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值。
-
引用文件
<properties resource="org/mybatis/example/config.properties">
-
把原本的改成如下即可
<dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource>
4、类型别名(typeAliases)
4.1、类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写
<typeAliases>
<typeAlias type="edu.hunan.pojo.User" alias="hello"/>
</typeAliases>
4.2、也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean
<typeAliases>
<package name="domain.blog"/>
</typeAliases>
4.3、使用注解,前提是必选要扫描包也就是必须要有第二种方法
@Alias("author")
public class Author {
...
}
注意点:接口名(UserMapper)和映射文件名(UserMapper.xml)一致!
5、映射器(mappers)
<mappers>
<!-- 使用相对于类路径的资源引用-->
<!-- <mapper resource="edu/hunan/dao/mapper.xml"/>-->
<!-- 接口的全路径-->
<!-- <mapper class="edu.hunan.dao.UserMapper"/>-->
<!-- 将包内的映射器接口实现全部注册为映射器,也就是包内的所有内容-->
<package name="edu.hunan.dao"/>
</mappers>
方式一:
<!-- 使用相对于类路径的资源引用-->
<!-- <mapper resource="edu/hunan/dao/mapper.xml"/>-->
方式二:
<!-- 接口的全路径-->
<!-- <mapper class="edu.hunan.dao.UserMapper"/>-->
方式三:
<!-- 将包内的映射器接口实现全部注册为映射器,也就是包内的所有内容-->
<package name="edu.hunan.dao"/>
注意点:
- 接口和他的Mapper配置文件必须同名!
- 接口和他的Mapper配置文件必须在同一个包下!
5、ResultMap结果集映射
resultMap 元素是 MyBatis 中最重要最强大的元素。
实际就是属性中的字段和数据库中的字段名称不一致!就需要用到resultMap标签了
5.1、方式一:resultMap
<resultMap id="hello" type="word">
<!-- property:属性中的字段,column:数据库中的字段-->
<result property="agea" column="age"/>
</resultMap>
<select id="select" resultMap="hello">
select * from student
</select>
5.2、方式二:起别名
select name,id,age as agea from student
注:方式二不建议使用,太小儿科!
6、日志
6.1、普通日志:
-
使用STDOUT_LOGGING,在MyBatis核心文件MyBatis.xml中配置
<settings> <!-- 标准的日志--> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>
6.2、LOG4J
-
创建一个log4j.properties文件
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码 log4j.rootLogger=DEBUG,console,file #控制台输出的相关设置 log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.Target = System.out log4j.appender.console.Threshold=DEBUG log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=[%c]-%m%n #文件输出的相关设置 log4j.appender.file = org.apache.log4j.RollingFileAppender log4j.appender.file.File=./log/hunan.log log4j.appender.file.MaxFileSize=10mb log4j.appender.file.Threshold=DEBUG log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=[%p][hhh%d{yy-MM-dd}][%c]%m%n #日志输出级别 log4j.logger.org.mybatis=DEBUG log4j.logger.java.sql=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.ResultSet=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG
-
MyBatis核心文件MyBatis.xml中配置
<settings> <!-- 需要导入第三方配置文件--> <!-- <setting name="logImpl" value="LOG4J"/>--> </settings>
-
测试
static Logger logger = Logger.getLogger(UserTest.class); @Test public void log(){ logger.info("这是info的方法"); logger.debug("这是dubug的方法"); logger.error("这是error的方法"); }
7、Limit实现分页
7.1、Sql中Limit分页
select * from student limit 0,2
7.2、MyBatis中使用Limit分页
-
接口
//分页 List<User> getlimit(Map<String,Object> map);
-
编写Mapper.xml中的sql的语句
<!-- 分页--> <select id="getlimit" parameterType="map" resultMap="hello"> select * from student limit #{index},#{page} </select>
-
测试
//分页 @Test public void limit(){ SqlSession session = MyBatisUtils.getSession(); UserMapper mapper = session.getMapper(UserMapper.class); Map<String, Object> map = new HashMap<>(); map.put("index",2); map.put("page",4); List<User> getlimit = mapper.getlimit(map); for (User user : getlimit) { System.out.println(user); } session.commit(); session.close(); }
8、使用注解开发
8.1、使用注解开发
-
注解在接口上实现
@Select("Select * from student") List<User> getUser();
-
需要在核心配置文件中绑定接口
<mappers> <mapper class="edu.hunan.dao.UserMapper"/> </mappers>
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。
8.2、CRUD
-
Select
//查询全部用户 @Select("Select * from student") List<User> getUser(); //根据iD查询用户 @Select("select * from student where id=#{id}") User getById(@Param("id") int id);
-
Update
//update @Update("update student set name=#{name} where id=#{id}") int getupdate(User user); //update @Update("update student set name=#{name1} where id=#{id1}") int getyupdate(Map<String,Object> map);
-
Insert
//insert @Insert("insert into student(id,name,age) values(#{id},#{name},#{agea})") int getInsert(User user);
-
Delete
//delete @Delete("delete from student where id=#{id}") int getdelete(@Param("id") int id);
测试类
【注意:我们必须要将接口注册绑定到我们的核心配置文件中!!】
关于@Param()注解
- 基本类型的参数或者String类型,需要加上
- 引用类型不需要加(User,Map等)
- 如果只有一个基本类型的话,可以忽略,但是建议加上!
- 我们在SQL中引用的就是我们这里的@Param(“”)中设定的属性名!
9、多对一处理
9.1、多对一:
- 多个学生,对应一个老师
- 对于学生而言,关联…多个学生,关联一个老师 【多对一】
- 对于老师而言,集合,一个老师,有很多学生【一对多】
9.2、测试环境搭建
- 新建实体类 Teacher,Student
- 建立Mapper接口
- 建立Mapper.XML文件
- 在核心配置文件中绑定注册我们的Mapper接口或者文件!【既映射器的三种方式】
- 测试查询是否能够成功!
9.3、按照结果处理
<!-- 方式二:根据结果查询-->
<resultMap id="word" type="Student">
<result property="id" column="id1"/>
<result property="name" column="name1"/>
<association property="teacher" column="tid">
<result property="name" column="tname"/>
</association>
</resultMap>
<select id="getSelect2" resultMap="word">
select s.id id1,s.name name1,w.name tname
from student1 s ,teacher w where s.tid =w.id
</select>
9.4、按照查询嵌套处理(子查询)
<!-- 方式一:查询嵌套方式处理:相当于子查询-->
<resultMap id="Hello" type="Student">
<association property="teacher" column="tid" javaType="Teacher" select="gettarcher"/>
</resultMap>
<select id="selectstudent" resultMap="Hello">
select * from student1
</select>
<select id="gettarcher" resultType="Teacher">
select * from teacher where id = #{id}
</select>
<!-- 一个老师一个学生 一对一-->
<resultMap id="c" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" column="tid">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
</association>
</resultMap>
<select id="students" resultMap="c">
SELECT s.id sid, s.name sname , t.name tname, t.id tid
FROM student s,teacher t
WHERE s.tid = t.id
</select>
回顾MySql多对一的查询方式:
- 子查询
- 联表查询
10、一对多处理
10.1、按照结果处理
<resultMap id="s" type="Teacher">
<!-- <result property="id" column="tid"/>-->
<result property="name" column="tname"/>
<result property="id" column="tid"/>
<collection property="students" ofType="Student">
<result property="id" column="sid" />
<result property="name" column="sname" />
<result property="tid" column="tid" />
</collection>
</resultMap>
<select id="getTeacher" resultMap="s">
select s.id sid, s.name sname , t.name tname, t.id tid
from student1 s,teacher t
where s.tid = t.id and t.id=#{id}
</select>
10.2、按查询嵌套处理
<select id="getTeacher2" resultMap="word">
select * from teacher where id = #{id}
</select>
<resultMap id="word" type="Teacher">
<collection property="students" column="id" javaType="ArrayList" ofType="Student" select="s"/> </resultMap>
<select id="s" resultType="Student">
select * from student1 where tid=#{id}
</select>
<!-- 一个老师多个学生 一对多-->
<resultMap id="c" type="Teacher">
<result property="id" column="id"/>
<result property="name" column="tname"/>
<collection property="student" ofType="Student">
<result column="id" property="id"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
<select id="students" resultMap="c">
SELECT t.name tname,s.name sname FROM teacher t,student s WHERE s.tid= t.`id`
</select>
小结
1、关联-association
- 对象里有对象使用 association 对象当做成员变量 组合关系 一对一关联(has one) 一个学生一个老师
2、集合-collection
- 对象里有集合使用 collection 集合当做成员变量 组合关系 一对多关联(has many) 一个老师多个学生
3、所以association是用于一对一和多对一,而collection是用于一对多的关系
4、JavaType和ofType都是用来指定对象类型的
- JavaType是用来指定pojo中属性的类型
- ofType指定的是映射到list集合属性中pojo的类型。
注意说明:
1、保证SQL的可读性,尽量通俗易懂
2、根据实际要求,尽量编写性能更高的SQL语句
3、注意属性名和字段不一致的问题
4、注意一对多和多对一 中:字段和属性对应的问题
5、尽量使用Log4j,通过日志来查看自己的错误
11、动态SQL
什么是动态SQL:动态SQL就是指根据不同的条件实现不同的SQL语句
利用动态SQL这一特性可以彻底摆脱这种痛苦。
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
if
choose (when, otherwise)
trim (where, set)
foreach
11.1、坏境搭建
-
创建Sql表
CREATE TABLE `blog` ( `id` varchar(50) NOT NULL COMMENT '博客id', `title` varchar(100) NOT NULL COMMENT '博客标题', `author` varchar(30) NOT NULL COMMENT '博客作者', `create_time` datetime NOT NULL COMMENT '创建时间', `views` int(30) NOT NULL COMMENT '浏览量' ) ENGINE=InnoDB DEFAULT CHARSET=utf8
-
插入元素
INSERT INTO `blog`(`id`,`title`,`author`,`create_time`,`views`)VALUES('5','html','鹏','2010-05-12 15:21:12','12');
-
创建一个基础工程(这里跟之前创建工程不凑不变)
-
编写核心配置文件
-
编写实体类
public class blog { private String id; private String title; private String author; private Date createTime; private int views;
-
编写实体类对应的Mapper接口和Mapper.xml文件
-
-
IDutil工具类
public class IDUtil { public static String genId(){ return UUID.randomUUID().toString().replaceAll("-",""); } }
-
mybatis核心配置文件,下划线驼峰自动转换
<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>
11.2、if语句
需求:根据作者名字和博客名字来查询博客!如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询
-
编写接口
List<blog> getblog(Map map);
-
编写SQL语句
<!--需求1: 根据作者名字和博客名字来查询博客! 如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询 <select id="getblog" parameterType="map" resultType="edu.hunan.pojo.blog"> select * from blog where <if test="author != null"> author = #{author} </if> <if test="title != null"> and title = #{title} </if> </select>
-
测试
@Test public void a(){ SqlSession session = MyBatisUtils.getSession(); mapper mapper = session.getMapper(mapper.class); Map<String, String> Map = new HashMap<String,String>(); Map.put("title","Spring"); Map.put("author","鹏"); List<blog> getblog = mapper.getblog(Map); for (blog blog : getblog) { System.out.println(blog); } session.close(); }
11.3、choose、when、otherwise语句
-
Sql语句
<select id="getblog" parameterType="map" resultType="edu.hunan.pojo.blog"> select * from blog <where> <choose> <when test="author != null"> author = #{author} </when> <when test="title != null"> and title = #{title} </when> <otherwise> and views = #{views} </otherwise> </choose> </where> </select>
-
测试
Map<String, String> Map = new HashMap<String,String>(); // Map.put("title","Spring"); Map.put("author","鹏"); Map.put("views","10"); List<blog> getblog = mapper.getblog(Map); for (blog blog : getblog) { System.out.println(blog); }
11.4、Set语句
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)
-
SQL语句
<update id="updata" parameterType="map"> update blog <set> <if test="title !=null"> title =#{title}, </if> <if test="author !=null"> author=#{author} </if> </set> where id=#{id} </update>
-
测试
public void updata(){ SqlSession session = MyBatisUtils.getSession(); mapper mapper = session.getMapper(mapper.class); Map<String, String>Map = new HashMap<>(); Map.put("id","1"); Map.put("title","Mysql"); Map.put("author","罗"); int updata = mapper.updata(Map); System.out.println(updata); }
11.5、where标签
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除*
-
SQl语句
<select id="getblog2" parameterType="map" resultType="edu.hunan.pojo.blog"> select * from blog <where> <if test="title!=null"> title=#{title} </if> <if test="author!=null"> and author=#{author} </if> </where> </select>
11.6、SQL片段
有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。
-
提取SQL片段
<sql id="idsql"> <if test="title !=null"> title =#{title} </if> <if test="author !=null"> and author=#{author} </if> </sql>
-
引用SQL片段
<select id="select" parameterType="map" resultType="edu.hunan.pojo.blog"> select * from blog <where> <include refid="idsql"></include> </where> </select>
11.7、Foreach
将数据库中前三个数据的id修改为1,2,3;
需求:我们需要查询 blog 表中 id 分别为1,2,3的博客信息
-
编写接口
//foreach查询 List<blog> foreach(Map map);
-
编写SQL语句
<select id="foreach" parameterType="map" resultType="blog"> select * from blog <where> <!-- collection:指定输入对象中的集合属性 item:每次遍历生成的对象 open:开始遍历时的拼接字符串 close:结束时拼接的字符串 separator:遍历对象之间需要拼接的字符串 select * from blog where 1=1 and (id=1 or id=2 or id=3) --> <foreach item="id" collection="list" open ="and (" close =")" separator="or"> id=#{id} </foreach> </where> </select>
-
测试
//foreach标签 @Test public void foreach(){ SqlSession session = MyBatisUtils.getSession(); mapper mapper = session.getMapper(mapper.class); List<Integer> list = new ArrayList<Integer>(); list.add(1); Map Map = new HashMap(); Map.put("li st",list); List<blog> foreach = mapper.foreach(Map); System.out.println(foreach); session.close(); }
动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了!
建议:
- 先在Mysql中写出完整的SQL再对应的去修改成为我们的动态SQL实现通用即可!
12、缓存
12.1、MyBatis缓存
- MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。 为了使它更加强大而且易于配置,我们对 MyBatis 3 中的缓存实现进行了许多改进。
- MyBatis系统中默认定义了两极缓存:一级缓存和二级缓存
- 默认情况下,只有一级缓存开启。(SqlSession级别缓存,也称本地缓存)
- 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
- 为了提高扩展性,MyBatis定义了缓存接口Cache.我们可以通过实现Cache接口来自定义二级缓存
12.2、一级缓存
12.3、二级缓存
-
二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
-
基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
-
工作机制
-
- 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
- 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
- 新的会话查询信息,就可以从二级缓存中获取内容;
- 不同的mapper查出的数据会放在自己对应的缓存(map)中;
使用步骤:
-
开启全局缓存 【mybatis.xml】
<setting name="cacheEnabled" value="true"/>
-
去每个mapper.xml中配置使用二级缓存,这个配置非常简单;【xxxMapper.xml】
-
默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:
<cache/>
<cache/>
官方示例=====>查看官方文档
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
-
测试
//缓存,根据Id查询用户 @Test public void selectId(){ SqlSession session = MyBatisUtils.getSession(); mapper mapper = session.getMapper(mapper.class); blog blog = mapper.selectId(1); System.out.println(blog); session.close(); SqlSession session2 = MyBatisUtils.getSession(); mapper mapper2 = session2.getMapper(mapper.class); blog blog2 = mapper2.selectId(1); System.out.println(blog2); session2.close(); }
小结:
- 只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据
- 查出的数据都会被默认先放在一级缓存中
- 只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中
13、mybatis-generator
1、mybatis-generator介绍
官方文档:http://mybatis.org/generator/running/running.html
MyBatis Generator (MBG) 是 MyBatis MyBatis的代码生成器。它将为所有版本的 MyBatis 生成代码。它将内省一个数据库表(或多个表)并生成可用于访问表的工件。这减少了设置对象和配置文件以与数据库表交互的初始麻烦。MBG 试图对大量简单的 CRUD(创建、检索、更新、删除)的数据库操作产生重大影响。您仍然需要为连接查询或存储过程编写 SQL 和对象代码。
MBG 生成不同风格和不同语言的代码,这取决于它的配置方式。例如,MBG 可以生成 Java 或 Kotlin 代码。MBG 可以生成与 MyBatis3 兼容的 XML - 尽管现在被认为是 MBG 的遗留用途。生成代码的较新样式不需要 XML。
mybatis-generator类似于mybatis-plus
2、在meven中的pom.xml配置
<plugins>
<plugin>
<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-maven-plugin -->
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<!--配置文件的位置--> <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
<executions>
<execution>
<id>Generate MyBatis Artifacts</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
3、配置mybatis-generator配置文件(官方文档:http://mybatis.org/generator/configreference/xmlconfig.html)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--mysql 连接数据库jar 这里选择自己本地位置-->
<classPathEntry location="C:\Users\请叫我鹏鹏君\.m2\repository\mysql\mysql-connector-java\5.1.47\mysql-connector-java-5.1.47.jar" />
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/springboot" userId="root"
password="123456">
</jdbcConnection>
<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和
NUMERIC 类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成PO类的位置 -->
<javaModelGenerator targetPackage="edu.hunan.pojo"
targetProject="src/main/java">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置
如果maven工程只是单独的一个工程,targetProject="src/main/java"
若果maven工程是分模块的工程,targetProject="所属模块的名称",例如:
targetProject="ecps-manager-mapper",下同-->
<sqlMapGenerator targetPackage="mapper"
targetProject="src/main/resources/MyBatis">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="edu.hunan.mapper"
targetProject="src/main/java">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 指定数据库表 -->
<table schema="" tableName="yonghu"></table>
<table schema="" tableName="shuxingzhi"></table>
<table schema="" tableName="shuxing"></table>
<table schema="" tableName="pingjia"></table>
<table schema="" tableName="fenlei"></table>
<table schema="" tableName="dingdan"></table>
<table schema="" tableName="dingdanxiang"></table>
<table schema="" tableName="chanpintupian"></table>
<table schema="" tableName="chanpin"></table>
</context>
</generatorConfiguration>
4、在maven中运行
14、参数详解
1、@Param
@Param的作用就是给参数命名,比如在mapper里面某方法A(int id),当添加注解后A(@Param("userId") int id),也就是说外部想要取出传入的id值,只需要取它的参数名userId就可以了。将参数值传如SQL语句中,通过#{userId}进行取值给SQL的参数赋值。
当使用了@Param注解来声明参数的时候,SQL语句取值使用#{},${}取值都可以。
当不使用@Param注解声明参数的时候,必须使用的是#{}来取参数。使用${}方式取值会报错。
**不使用@Param注解时,参数只能有一个,并且是Javabean。**在SQL语句里可以引用JavaBean的属性,而且只能引用JavaBean的属性。
多个参数必须要加@Param注解,否则报错
15、映射关系
<?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="com.klr.coordination.mapper.CooperateWithMapper">
<resultMap type="Consultation" id="ConsultationResult">
<result property="id" column="kcid" />
<result property="mechanismId" column="mechanism_id" />
<result property="userId" column="user_id" />
<result property="meetingTheme" column="meeting_theme" />
<result property="meeting_time" column="meetingTime" />
<result property="meetingAddress" column="meeting_address" />
<result property="fillUserId" column="fill_user_id" />
<result property="meetingTakenotes" column="meeting_takenotes" />
<result property="isStatus1" column="isstatus1" />
<result property="sendId" column="send_id" />
<result property="sendTime" column="send_time" />
<result property="status" column="status"/>
<result property="kpwUserid" column="kpwUserid"/>
<result property="kpwMeetingid" column="kpwMeetingid"/>
<result property="patientId" column="patient_id"/>
<result property="sendId" column="send_id"/>
<result property="isRead" column="is_read"/>
</resultMap>
<sql id="getLists">
SELECT
p.id as kcid,p.mechanism_id,p.meeting_takenotes,w.user_id as kpwUserid,w.meeting_id as kpwMeetingid,p.patient_id,
p.send_id,p.send_time,p.is_read,p.is_status as isstatus1 ,
p.meeting_theme,p.meeting_time,p.meeting_address,w.is_status as status
FROM
`klr_consultation` p
LEFT JOIN klr_meeting_participant w ON w.meeting_id = p.id
</sql>
<select id="getList" resultMap="ConsultationResult">
<include refid="getLists" />
<where>
( p.send_id = #{sendId} OR w.user_id = #{sendId})
<if test="userId != null"> AND p.send_id = #{userId}</if>
<if test="startTime != null"> AND p.send_time >= #{startTime} </if>
<if test="entTime != null"> AND p.send_time <= #{entTime}</if>
ORDER BY p.meeting_time desc
</where>
</select>
</mapper>