MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了[google code](https://baike.baidu.com/item/google code/2346604),并且改名为MyBatis 。2013年11月迁移到Github。 如果获取Mybatis
maven
org.mybatis mybatis3.5.6
github
https://github.com/mybatis/mybatis-3.git
中文文档
https://github.com/mybatis/mybatis-3.git
持久化持久化就是将瞬时状态转换为持久状态的一个过程。内存:断电即失,瞬时性数据库(jdbc),io文件持久化生活:冷藏,罐头
为什么需要持久化?
有些数据不能丢失内存太贵了 持久层
Dao层,Service层,Controller层
完成持久化工作的代码块底层界限十分明显 为什么学习Mybatis
让开发人员更容易将数据持久化(存储数据库)方便传统的JDBC太复杂了,简化,框架,自动化不用Mybatis也可以,更容易上手,技术没有高低之分优点
简单易学灵活: sql写在xml里,便于统一管理和优化。通过sql语句可以满足 *** 作数据库的所有需求。解除sql与程序代码的耦合 sql和代码的分离,提高了可维护性。提供映射标签,支持对象与数据库的orm字段关系映射提供对象关系映射标签,支持对象关系组建维护提供xml标签,支持编写动态sql。 [2]使用的人多 学习方法
- 准备环境导入依赖或包编写代码测试
CREATE DATAbase `mybatis` USE `mybatis` DROp TABLE IF EXISTS `user`; CREATE TABLE `user`( `id` INT(20) NOT NULL, `name` VARCHAr(30) DEFAULT NULL, `pwd` VARCHAr(10), PRIMARY KEY(`id`) )ENGINE = INNODB CHARSET=utf8创建项目
创建父工程mybatis-study,创建子工程mybatis-01,在父工程中添加依赖
编写代码mysql mysql-connector-java5.1.46 org.mybatis mybatis3.5.7 junit junit4.13.2
编写配置文件
编写java工具类
package com.hopeful.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 MyBatisUtils { private static SqlSessionFactory sqlSessionFactory; static { try { String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream = null; inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } private static SqlSession getSqlSession() { return sqlSessionFactory.openSession(); } }pojo类
package com.hopeful.pojo; public class User { private int id; private String name; private String pwd; public User() { } public User(int id, String name, String pwd) { this.id = id; this.name = name; this.pwd = pwd; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + ''' + ", pwd='" + pwd + ''' + '}'; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } }dao层
package com.hopeful.dao; import com.hopeful.pojo.User; import java.util.List; public interface UserDao { Listmapper文件getUserList(); }
可能出现的问题
配置文件没有注册(mybatis-config.xml文件中未注册mapper文件)maven导出资源问题 可能出现的问题 问题1:资源无法加载,比如java目录下的xml文件
解决方案,配置资源的路径,因为默认加载resource的特定目录
xml(UserMapper.xml)文件src/main/java ***.properties ***.properties ** List getUserList();
测试
@Test public void testSelectList() { // try{}catch(){}finally{} 官网推荐写法 SqlSession sqlSession = null; try { sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Listinsert mapper(userMapper.java)接口文件userList = mapper.getUserList(); for (User user : userList) { System.out.println(user); } }catch (Exception e) { System.out.println(e.getMessage()); }finally { sqlSession.close(); } }
int insertUser(User user);xml(UserMapper.xml)文件
测试insert into user(id,name,pwd) value (#{id},#{name},#{pwd})
@Test public void insertUser() { SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); int count = mapper.insertUser(new User(4, "晨晨", "123123")); if(count > 0) { System.out.println("插入成功"); } // 提交事务 sqlSession.commit(); // sqlSession.commit(true); sqlSession.close(); }update
mapper(userMapper.java)接口文件
update user set name=#{name},pwd=#{pwd} where id = #{id};
其它可参考上方写法。
deletemapper(userMapper.java)接口文件
delete from user where id = #{id}
其它可参考上方写法。
常见问题sqlSession忘记关闭
sqlSession.close();
事务未提交,导致数据未更新
// 提交事务 sqlSession.commit();
mappe.xml文件中的标签匹配错误resource绑定mapper,需要使用路径mybatis配置文件必须符合规范NullPointerException,没有注册到资源输出的xml文件中存在中文乱码问题maven资源没有导出问题 万能的map
mapper接口文件
int insertUserByMap(HashMapuser);
mapper.xml文件
insert into user(id,name,pwd) value (#{id},#{username},#{password})
测试代码
@Test public void insertUserByMap() { SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); HashMapmap = new HashMap (); map.put("id",5); map.put("username","狂神"); map.put("password","666666"); int count = mapper.insertUserByMap(map); if(count > 0) { System.out.println("插入成功"); } // 提交事务 sqlSession.commit(); // sqlSession.commit(true); sqlSession.close(); }
总结:
传递的参数为map,直接在sql中获取key即可 parameterType=“map”传递的参数是实体类对象,直接在通过对象的属性获取即可 parameterType="[实体类对象类型]"传递的参数是一个基本数据类型,直接通过参数名获取即可 parameterType="[基本数据类型]",也可省略如果传递多个参数,用map或,或者注解(@Param) 模糊查询
mapper.java文件
ListgetUserList2(String value);
java 代码执行的时候,传递通配符%%
mapper.xml文件
select * from user where name like #{value}
测试代码
ListuserList2 = mapper.getUserList2("%狂%");
在sql拼接中使用通配符
mapper.xml文件
select * from user where name like "%"#{value}"%"
测试代码
ListuserList2 = mapper.getUserList2("狂");
配置文件
mybatis核心配置文件为mybatis-config.xml(也可以为其它名称)
configuration(配置)
properties(属性)(需要掌握)settings(设置)(需要掌握)typeAliases(类型别名)(需要掌握)typeHandlers(类型处理器)objectFactory(对象工厂)plugins(插件)
mybatis-plusmybatis-generator-core通用mapper environments(环境配置)(掌握)
environment(环境变量)
transactionManager(事务管理器)dataSource(数据源) databaseIdProvider(数据库厂商标识)mappers(映射器) 属性 properties
在外部进行配置 java属性文件中配置也可以进行动态配置也可以在 properties 元素的子元素中设置
db.properties
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8 username=root password=root
mybatis-config.xml
注意:
可以直接引入配置文件
mybatis-config 配置加载
首先读取在 properties 元素体内指定的属性。
然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。
因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。
配置文件属性的优先级高于properties标签中子元素的属性值。即properties子元素中填写错误连接信息,而配置文件填写正确信息,仍可连接,反之无法连接。
mybatis-config 中configuration标签内的子标签必须按照顺序书写,即properties,…environment,…mapper等顺序
properties中 url 和 resources 的区别
环境配置(environments)mybatis可配置多种环境,比如生产,测试,开发环境不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
关键点:
默认使用的环境ID,比如default=“development”每个环境定义的环境ID,比如id=“development”事务管理器的配置,比如type=“JDBC”数据源的配置,type=“POOLED”默认环境和环境ID可以随便命名,但是默认的环境 ID 要匹配其中一个环境 ID。mybatis默认的事务管理是 JDBC,默认的数据源是 POOLED 事务管理器(transactionManager)
MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):
JDBC 这个配置直接使用了 JDBC 的提交和回滚设置,它依赖从数据源获得的连接来管理事务作用域。MANAGED MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接 默认情况下它会关闭连接。将 closeConnection 属性设置为 false 来阻止默认的关闭行为 数据源(dataSource)
有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]"):
UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,减少了创建的时间,提高了效率JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用
连接数据库 dbcp c3p0 druid
映射器(mappers)类型别名(typeAliases)
类型别名,可以缩短全限定类名的书写。
指定一个实体类别名
select * from user;
指定一个包名
在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。比如 com.hopeful.pojo.User 的别名为 user;若有注解,则别名为其注解值。
如果实体类少,可以使用第一种(指定实体类的方法)
如果实体类多,建议使用第二种(指定报名的方法),如果需要修改别名,需要通过注解
@Alias("UserAlias") public class User {}
常见的 Java 类型内建的类型别名
不区分大小写基本数据类型,前面多"_",比如 _byte -> byte包装数据类型,用基本数据类型,比如byte -> Byte参看官网文档:https://mybatis.org/mybatis-3/zh/configuration.html 设置(settings)
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
常用的设置
生命周期和作用域sqlSessionFactoryBuilder
一旦创建了 SqlSessionFactory,就不再需要它了佳作用域是方法作用域(也就是局部方法变量)可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好被释放 sqlSessionFactory
一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次因此 SqlSessionFactory 的最佳作用域是应用作用域。最简单的就是使用单例模式或者静态单例模式。 sqlSession
每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享最佳的作用域是请求或方法作用域。 结果集映射
问题:当属性值和数据库字段不一样时,有两种解决方案
起别名
resultMap
resultMap
resultMap 元素是 MyBatis 中最重要最强大的元素。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。ResultMap 的优秀之处——你完全可以不用显式地配置它们。属性名和字段名不一致进行配置,一致的话可以不配置 日志工厂
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8KYKHxmo-1642922986891)(C:UsersAppleDesktop笔记Mybatis.assetsimage-20210727073432156.png)]
SLF4JLOG4J (掌握)LOG4J2JDK_LOGGINGCOMMONS_LOGGINGSTDOUT_LOGGING(标准日志,掌握)NO_LOGGING log4j 什么是Log4j?
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件我们也可以控制每一条日志的输出格式通过定义每一条日志信息的级别这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。 log4j的使用
添加依赖
添加配置文件log4j.propertieslog4j log4j1.2.17
#将等级为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/shun.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][%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-config.xml中设置log4j
测试代码查看日志
测试package com.hopeful.dao; import com.hopeful.pojo.User; import com.hopeful.utls.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.apache.log4j.Logger; import org.junit.Test; import java.util.List; public class testUserDao { static Logger logger = Logger.getLogger(testUserDao.class); @Test public void testLog4j() { logger.info("info: 进入了testLog4j方法"); logger.debug("info: 进入了testLog4j方法"); logger.error("info: 进入了testLog4j方法"); } }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wujlsw60-1642922986895)(C:UsersAppleDesktop笔记Mybatis.assetsimage-20210727214924449.png)]
常见问题.log文件打不开
方案一:
file -> setting -> Editor -> fileType -> text添加.log文件
如果还是不行,建议查看mybatis-config.xml的类型别名不要使用包扫描
分页
select * from user limit startIndex,pageSize; select * from user 3; [0,3]limit分页
添加接口方法
ListgetUserListByLimit(Map map);
添加userMapper.xml文件
select * from user limit #{startIndex},#{pageSize};
测试
@Test public void testSelectByLimit() { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); MapRowRounds分页map = new HashMap (); map.put("startIndex",3); map.put("pageSize",3); List userList = mapper.getUserListByLimit(map); for (User user : userList) { System.out.println(user); } sqlSession.close(); }
userMapper.java
ListgetUserListByRowBounds();
userMapper.xml
测试
static Logger logger = Logger.getLogger(testUserDao.class); @Test public void testSelectByLimit() { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); MappageHelpermap = new HashMap (); map.put("startIndex",3); map.put("pageSize",3); List userList = mapper.getUserListByLimit(map); for (User user : userList) { System.out.println(user); } sqlSession.close(); }
官网:https://pagehelper.github.io/
使用注解开发 面向接口编程p15:
大家之前都学过
mybatis注解另一种方法来完成语句映射,而可以使用 Java 注解来配置。
@Select("select * from user") ListgetUserList();
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的 *** 作,最好用 XML 来映射语句。
mybatis执行流程[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eWEO39zV-1642922986896)(Mybatis.assetsmybatis启动流程.png)]
注解CRUDuserMapper.java
@Insert("insert into user(id, name, pwd) value(#{id},#{name},#{password})") int insertUser(@Param("id") int id, @Param("name") String name, @Param("password") String password); @Update("update user set name = #{name}, pwd = #{password} where id = #{id}") int updateUser(@Param("id") int id, @Param("name") String name, @Param("password") String password); @Delete("delete from user where id = #{uid}") int deleteById(@Param("uid") int id);
测试
@Test public void testGetUserById() { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserById(2); System.out.println(user); sqlSession.close(); } @Test public void testInsertUser() { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.insertUser(10,"Hopeful","123567"); sqlSession.close(); } @Test public void testUpdateUser() { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.updateUser(10,"晨晨","abcef"); sqlSession.close(); } @Test public void testDeleteById() { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.deleteById(10); sqlSession.close(); }@Param
该注解用于标识参数
如果基本数据类型或String类型,可用@Param注解
引用类型不用该注解(实体类,或map)
多个基本类型或String类型参数,需用@Param注解
一个基本类型或String类型参数,建议使用@Param注解(虽然不使用也可以)
如果使用该注解后,sql语句中的参数名称应该使用注解标记的属性名称
lombokLombok 是一个很方便的插件,本质是个 Java 库,使用它通过相关注解就可以不用再编写冗长的 getter 或者 equals 等方法了。
Lombok 注解思维导图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AkiJBSfl-1642922986897)([外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yqkGFrwv-1642922990809)(Mybatis.assetslombok.jpg)]]
Lombok 使用点击 File->Settings->Plugins,搜索 Lombok,然后点击安装 Lombok 插件:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fS8wjjuj-1642922986897)(Mybatis.assets/image-20210730131237530.png)]
首先在 pom 文件中引入依赖:
多对一 环境搭建 创建表org.projectlombok lombok1.18.12 provided
CREATE TABLE `teacher` ( `id` INT(10) NOT NULL, `name` VARCHAR(30) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8 INSERT INTO teacher(`id`, `name`) VALUES (1, 秦老师); CREATE TABLE `student` ( `id` INT(10) NOT NULL, `name` VARCHAR(30) DEFAULT NULL, `tid` INT(10) DEFAULT NULL, PRIMARY KEY (`id`), KEY `fktid` (`tid`), CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8INSERT INTO `student` (`id`, `name`, `tid`) VALUES (1, 小明, 1); INSERT INTO `student` (`id`, `name`, `tid`) VALUES (2, 小红, 1); INSERT INTO `student` (`id`, `name`, `tid`) VALUES (3, 小张, 1); INSERT INTO `student` (`id`, `name`, `tid`) VALUES (4, 小李, 1); INSERT INTO `student` (`id`, `name`, `tid`) VALUES (5, 小王, 1);测试
- properties
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8 username=root password=root
mybatis-config.xml
mybatisUtils
package com.hopeful.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 MybatisUtils { private static SqlSessionFactory sqlSessionFactory = null; static { try { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(true); } }
Student.java
package com.hopeful.pojo; import lombok.Data; @Data public class Student { private int id; private String name; private Teacher teacher; }
Teacher.java
package com.hopeful.pojo; public class Teacher { private int id; private String name; }
StudentMapper
package com.hopeful.dao; public interface StudentMapper { }
TeacherMapper
package com.hopeful.dao; import com.hopeful.pojo.Teacher; import org.apache.ibatis.annotations.Select; public interface TeacherMapper { @Select("select * from teacher") public Teacher getTeacherById(int id); }
Mytest
package com.hopeful.dao; import com.hopeful.pojo.Teacher; import com.hopeful.utils.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.junit.Test; public class MyTest { @Test public void testEnv() { SqlSession sqlSession = MybatisUtils.getSqlSession(); TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class); Teacher teacher = mapper.getTeacherById(1); System.out.println(teacher); } }
出现查询结果,证明环境没问题!
嵌套查询studentMapper.xml
连表查询select * from student; select * from teacher where id = #{tid}
studentMapper.xml
测试select s.id sid, s.name sname, t.id tid,t.name tName from student s,teacher t where s.tid = t.id
@Test public void testGetStudent2() { SqlSession sqlSession = MybatisUtils.getSqlSession(); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // Listlist = mapper.getStudentTeacherList(); List list = mapper.getStudentTeacherList2(); for (Student student : list) { System.out.println(student); } sqlSession.close(); }
总结:
嵌套查询,相当于子查询连表查询 一对多
环境搭建,同上
连表查询teacherMapper.xml
嵌套查询select t.id tid, t.name tName, s.id sid, s.name sName from teacher t, student s where s.tid = t.id
总结select * from teacher; select * from student where tid = #{tid}
嵌套查询 sql简单,映射复杂,不易调试
连表查询 sql复杂,映射简单,因sql书写完成,容易调试(推荐)
association - 关联 - 多对一
collection - 集合 - 一对多
javaType 实体类中的属性类型(如List)
ofType 集合中实体类 的类型
面试高频:
Mysql引擎InnDB底层原理索引索引优化 动态SQL
所谓动态SQL,本质上还是SQL语句,只是它会根据条件的不同,而拼接不同的SQL语句。
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
ifchoose (when, otherwise)trim (where, set)foreach 搭建环境
准备表
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;`mybatis`
创建一个基础工程(子项目)
创建module,并导包
编写配置文件(可参考上面环境搭建)
编辑工具类
MybatisUtils
public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory = null; static { try { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(true); } }
IDUtils
public class IDUtils { public static String getUUID() { return UUID.randomUUID().toString().replace("-",""); } }
编辑实体类对象
@Data public class Blog { private String id; private String title; private String author; private Date createTime; private int views; }
- 编写mapper文件和mapper文件对应的xml文件
BlogMapper
int insertBlog(Blog blog);
BlogMapper.xml
insert into blog(id, title, author, create_time, views) values (#{id}, #{title}, #{author}, #{createTime}, #{views})
测试
@Test public void testInsert() { SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Blog blog = new Blog(); blog.setId(IDUtils.getUUID()); blog.setTitle("Mybatis"); blog.setAuthor("Hopeful"); blog.setCreateTime(new Date()); blog.setViews(1200); mapper.insertBlog(blog); blog.setId(IDUtils.getUUID()); blog.setAuthor("狂神说"); blog.setTitle("Spring"); blog.setCreateTime(new Date()); blog.setViews(1000); mapper.insertBlog(blog); blog.setId(IDUtils.getUUID()); blog.setTitle("Mybatis"); blog.setAuthor("小菜鸟"); blog.setCreateTime(new Date()); blog.setViews(9000); mapper.insertBlog(blog); sqlSession.close(); }IF
BlogMapper
ListqueryBlogByIF(HashMap map);
BlogMapper.xml
select * from blog and title like concat('%',#{title},'%') and author like concat('%',#{author},'%')
使用技巧:
果参数为数字类型的时候没有特俗需求的情况只需要判断是否为null即可。
如果有特俗需求,例如判断是否大于某个数的时候才行。只需要加上对应的条件判断即可
特殊符号转义
如果为字符串类型
如果需要过滤空串,添加空串判断即可 不支持 && 所以这里用 and or || 来做逻辑与或的判断
如果判断字符串是否已某个特俗字符开头,结尾等。直接调用String的对应方法即可
注意:
但是参数类型为非字符串类型的时候就需要写成
仅仅写成
- 判断list是否为空
上面说过,if条件判断可以直接调用对象自身的方法进行逻辑判断,所以list判空。可以调用.size()>0或者.isEmpty()
测试
@Test public void testqueryBlogByIF() { SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMapchoosemap = new HashMap (); // map.put("title","Spring"); // map.put("author","狂神说"); List blogs = mapper.queryBlogByIF(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
ListqueryBlogByChoose(HashMap map);
select * from blog and title like concat('%', #{title},'%') and author like concat('%', #{author},'%') and views = 9999
测试
@Test public void testqueryBlogByChoose() { SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMapsetmap = new HashMap (); map.put("title","Spring"); map.put("author","Hopeful"); map.put("views",1000); List blogs = mapper.queryBlogByChoose(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
BlogMapper.java
int updateBlogBySet(HashMap map);
BlogMapper.xml
update blog where id = #{id} title = #{title}, author = #{author},
测试
// 条件都不满足时 会出现sql语法错误 @Test public void testupdateBlogBySet() { SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMapSQL 片段map = new HashMap (); // map.put("title","java如此简单"); // map.put("author","小菜鸟"); // map.put("id","86120dda6b3e45a6a06202895cd2b459"); mapper.updateBlogBySet(map); sqlSession.close(); }
所谓SQL片段,就是将sql中重复的部分抽取出来,通过在需要的地方进行引用,以达到复用的目的。
title = #{title}, author = #{author}, update blog where id = #{id}
测试代码,如上。
所谓的动态SQL,本质上还是SQL,只是在SQL代码的基础上,添加一些逻辑代码。
ForeachBlogMapper.java
ListqueryBlogByForeach(HashMap map);
BlogMapper.xml
select * from blog id = #{id}
测试
@Test public void testqueryBlogByForeach() { SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMapmap = new HashMap (); ArrayList ids = new ArrayList (); ids.add("86120dda6b3e45a6a06202895cd2b459"); ids.add("b757564a6b374eb9b4c6d2cf96b86d21"); ids.add("187be67b9340405e81daa31886501173"); map.put("ids",ids); mapper.queryBlogByForeach(map); sqlSession.close(); }
总结
动态SQL,其实就是在拼接SQL语句,只要保证SQL语句语法的合法性,进行排列组合就好了
foreach使用
将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。 缓存 简介
查询数据时,需要连接数据库,比较消耗资源,为了提高查询效率,需要将查询的数据存放到一个可以提取的地方 (内存),当再次查询相同的数据时,不用连接数据库直接取出内存中的数据,缓解数据库压力,提升查询效率。
- 什么是缓存【Cache】?
存在内存中的临时数据将用户经常查询的数据存放 缓存(内存)中,用户去查询数据就不用从磁盘(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。 什么使用缓存?
减少和数据库的交互次数,减少系统开销,提高系统效率。 什么样的数据能使用缓存?
经常查询,且不经常修改的数据。
Mybatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存,缓存可以极大地提高查询的效率。
Mybatis系统中默认定义了两级缓存,一级的缓存和二级缓存。
默认情况下,只有一级缓存开启(sqlSession级别的缓存,也成为本地缓存)
二级缓存需要手动启动和配置,他是基于namespace级别的配置。为了提高扩展性,MyBatis定义了缓存接口Cache,我们可以通过Cache接口来定义二级缓存。 一级缓存
一级缓存也叫本地缓存
与数据库同一次会话期间查询到的数据会放到本地缓存中以后如果需要获取相同的数据,直接从缓存中拿,无需再次查询数据库。
代码演示:
UserMapper.java
User queryUserById(int id);
UserMapper.xml
select * from mybatis.user where id = #{id}
测试
@Test public void testQueryUserById() { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.queryUserById(1); System.out.println(user); // mapper.updateUser(new User(1,"Hopeful","abc")); // User user2 = mapper.queryUserById(3); // 关闭缓存,第二次查询相同的数据还会查询数据库 sqlSession.clearCache(); User user2 = mapper.queryUserById(1); System.out.println(user2); sqlSession.close(); }
注意点
一级缓存的作用域是SQLSession中,即一次连接数据库到关闭这个连接有效查询相同的数据,第一次查询数据库,其他查询从缓存中获取
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ShnjIrH-1642922986898)(Mybatis.assets/image-20210902063606063.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S2G4DPf8-1642922986898)(Mybatis.assets/image-20210902063632833.png)]
数据库查询一次!
缓存失效
查询不同的数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0bmBCl8w-1642922986899)(Mybatis.assets/image-20210902063746094.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WJXHzQDB-1642922986900)(Mybatis.assets/image-20210902063823939.png)]
增删改,会刷新缓存(因为此类 *** 作会修改数据)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BzgHpyxF-1642922986901)(Mybatis.assets/image-20210902063923688.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b8VtF3gy-1642922986901)(Mybatis.assets/image-20210902064007039.png)]
查询不同的mapper手动清除缓存
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tk3niOPV-1642922986901)(Mybatis.assets/image-20210902064118100.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wJ9gAw6K-1642922986902)(Mybatis.assets/image-20210902064148444.png)]
一级缓存就是一个Map。
二级缓存二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存。基于namespace级别的缓存,一个命名空间,对应一个二级缓存工作机制:
一个会话查询一条数据,这个数据就会被放在当前会话中的一级缓存中如果当前会话关闭了,这个会话对应的一级缓存就没了;如果我们想要的是,会话关闭了,一级缓存被保存到二级缓存中新的会话查询信息中,就可以从二级缓存中获取内容不同的mapper查出的数据会放在自己对应的缓存(map)中
开启二级缓存的步骤:
在mybatis-config.xml文件中显示开启二级缓存
在userMapper.xml文件中添加标签
也可以根据需求定义一些属性
Bill
package com.hopeful.pojo; import lombok.Data; import java.math.BigDecimal; @Data public class Bill extends baseEntity { private Integer id; // id private String billCode; // 账单编码 private String productName; //商品名称 private String productDesc; //商品描述 private String productUnit; //商品单位 private BigDecimal productCount; //商品数量 private BigDecimal totalPrice; //总金额 private Integer isPayment; //是否支持 private Integer providerId; //供养商ID private String providerName; //供应商名称 }Provider
package com.hopeful.pojo; public class Provider extends baseEntity { private Integer id; // id private String proCode; //供养商编码 private String proDesc; //供养商描述 private String proContact; //供养商联系人 private String proPhone; //供养商电话 private String proAddress; // 供养商地址 private String proFax; //供应商传真 private String companyLicPicPath; //企业营业执照的存储路径 private String orgCodePicPath; //组织机构的代码证的存储路径 }Role
package com.hopeful.pojo; public class Role extends baseEntity { private Integer id; // id private String roleCode; //角色编码 private String roleName; //角色名称 }User
package com.hopeful.pojo; import java.util.Date; public class User extends baseEntity{ private Integer id; // id private String userCode; // 用户编码 private String userName; //用户名称 private String userPassword; //用户密码 private Integer gender; //性别 private Date birthday; private String phone; //电话 private String address; //地址 private Integer userRole; //用户角色 private Integer createdBy; //创建者 private Date creationDate; //创建时间 private Integer modifyBy; //更新者 private Date modifyDate; //更新时间 private Integer age;//年龄 private String userRoleName; //用户角色名称 }idea 关于MySQL设置 sql语句中字段提示 SpringSpring下载地址:https://repo.spring.io/ui/native/release/org/springframework/spring
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)