首页 文章 精选 留言 我的

精选列表

搜索[plus],共2860篇文章
优秀的个人博客,低调大师

EasyTrans 1.2.6 发布,Mybatis Plus 多表关联外键翻译组件

更新内容: 字典翻译缓存支持放到redis中 添加使用map的实现类包装vo 进行翻译(比如ruoyi的AjaxResult) 插件介绍: 表里我们经常存放字典码,外键 给前端展示的时候要展示字典描述 (比如 sex 0 代表男),外键要显示 title/name (如 userid 1 要翻译为张三)。字典比较简单,很多项目都直接交给前端翻译,但是外键翻译是必须要后台来做的,最常见的做法就是 表 join ,这样又要自己写 sql 比较麻烦。使用 Easy Trans,只需要一个注解就可以搞定数据翻译。 支持的场景: 字典翻译 把 sex 0 翻译为男 普通外键翻译 / 唯一键翻译 框架使用 mp/jpa 能力自动帮你去执行 sql 根据外键查询 name/title 并且 set 到你的 vo 字段上 跨微服务翻译 比如 order 集合 user 是 2 个微服务,但是 order 要展示创建人姓名,表里只有 id 可以使用跨微服务翻译 枚举翻译 把枚举中的汉字给到前端 Trans 注解: 程序员只需要掌握这一个注解就算熟练使用 EasyTrans 了,绝对不干让程序员掉更多头发的事情。 @Data @Builder @AllArgsConstructor @NoArgsConstructor //实现TransPojo 接口,代表这个类需要被翻译或者被当作翻译的数据源 public class Student implements TransPojo { // 字典翻译 ref为非必填 @Trans(type = TransType.DICTIONARY,key = "sex",ref = "sexName") private Integer sex; //这个字段可以不写,实现了TransPojo接口后有一个getTransMap方法,sexName可以让前端去transMap取 private String sexName; //SIMPLE 翻译,用于关联其他的表进行翻译 schoolName 为 School 的一个字段 @Trans(type = TransType.SIMPLE,target = School.class,fields = "schoolName") private String schoolId; //远程翻译,调用其他微服务的数据源进行翻译 @Trans(type = TransType.RPC,targetClassName = "com.fhs.test.pojo.School",fields = "schoolName",serviceName = "easyTrans",alias = "middle") private String middleSchoolId; // 枚举翻译,返回文科还是理科给前端 @Trans(type=TransType.ENUM,key = "desc") private StudentType studentType = StudentType.ARTS; public static enum StudentType{ ARTS("文科"), SCIENCES("理科"); private String desc; StudentType(String desc){ this.desc = desc; } } } 项目地址:https://gitee.com/fhs-opensource/easy_trans 文档地址:https://gitee.com/fhs-opensource/easy_trans/wikis

优秀的个人博客,低调大师

EasyTrans 1.2.4 发布,Mybatis Plus 多表关联外键翻译组件

更新内容: 支持表唯一键字段代替主键翻译(比如excel导入填写用户手机号,插入数据库的时候需要userid) 修复使用 @TransMethodResult 翻译方法返回值的时候,平铺不起作用的问题 修复vo中有循环嵌套 会引发无限循环问题 插件介绍: 表里我们经常存放字典码,外键 给前端展示的时候要展示字典描述(比如 sex 0 代表男),外键要显示title/name (如userid1 要翻译为张三)。字典比较简单,很多项目都直接交给前端翻译,但是外键翻译是必须要后台来做的,最常见的就是 表join ,这样又要自己写sql 比较麻烦。使用Easy Trans,只需要一个注解就可以搞定数据翻译。 支持的场景: 字典翻译 把sex 0翻译为男 普通外键翻译/唯一键翻译 框架使用mp/jpa能力自动帮你去执行sql根据外键查询name/title 并且set到你的vo字段上 跨微服务翻译 比如order集合user是2个微服务,但是order要展示创建人姓名,表里只有id 可以使用跨微服务翻译 枚举翻译 把枚举中的汉字给到前端 Trans注解: 程序员只需要掌握这一个注解就算熟练使用EasyTrans了,绝对不干让程序员掉更多头发的事情。 @Data @Builder @AllArgsConstructor @NoArgsConstructor //实现TransPojo 接口,代表这个类需要被翻译或者被当作翻译的数据源 public class Student implements TransPojo { // 字典翻译 ref为非必填 @Trans(type = TransType.DICTIONARY,key = "sex",ref = "sexName") private Integer sex; //这个字段可以不写,实现了TransPojo接口后有一个getTransMap方法,sexName可以让前端去transMap取 private String sexName; //SIMPLE 翻译,用于关联其他的表进行翻译 schoolName 为 School 的一个字段 @Trans(type = TransType.SIMPLE,target = School.class,fields = "schoolName") private String schoolId; //远程翻译,调用其他微服务的数据源进行翻译 @Trans(type = TransType.RPC,targetClassName = "com.fhs.test.pojo.School",fields = "schoolName",serviceName = "easyTrans",alias = "middle") private String middleSchoolId; // 枚举翻译,返回文科还是理科给前端 @Trans(type=TransType.ENUM,key = "desc") private StudentType studentType = StudentType.ARTS; public static enum StudentType{ ARTS("文科"), SCIENCES("理科"); private String desc; StudentType(String desc){ this.desc = desc; } } } 项目地址:https://gitee.com/fhs-opensource/easy_trans 文档地址:https://gitee.com/fhs-opensource/easy_trans/wikis

优秀的个人博客,低调大师

sqltoy-orm-4.18.22 发版,还在坚持 mybatis(plus) 吗?

开源地址: github:https://github.com/sagframe/sagacity-sqltoy gitee:https://gitee.com/sagacity/sagacity-sqltoy idea 插件(可直接在idea中检索安装):https://github.com/threefish/sqltoy-idea-plugins 更新内容 1、在findEntity中EntityQuery可以设置fetchSize,在sqltoyContext中可以全局设置fetchSize,实现查询数据提取的性能 2、针对一些特殊原因导致表名是数据库关键词场景的兼容 ORM的最佳形态:类JPA对象式操作+超强查询 jpa对象式操作:dao.save(entity)/saveAll(List<Entity>)/update(entity)/load(new Entity(id)) 模式,简单直接,对此大家基本能形成共识,也是各种ORM差异最小的。sqltoy在这个方面相信是对等的,因为是共识理论上来说不必要每次都提及! 2. 超强查询:最理想的状态就是:第一在数据库客户端调试好的sql 最直观高效的移入项目工程中;第二、在需求变化时最简单快速的可以从工程中放入数据库客户端中进行调试。也就是说要最大限度的保持sql的原始面貌; 用ORM我们真真正正的痛点是什么? 1、sql的编写和后期维护,上面的图例已经说明问题。 2、执行效率:当同样功能效率有几倍差距时其实就是天地之别了,带来的直接效果就是:一边是用户的高度夸赞、一边是用户的鄙视,您能理解这是什么差距吗? sqltoy的缓存翻译,大幅减少表关联简化sql,让你的查询性能成几何级提升 极致的分页,同样帮助你实现查询的性能大幅提升 快速分页:@fast() 实现先取单页数据然后再关联查询,极大提升速度 分页优化器:page-optimize 让分页查询由两次变成1.3~1.5次(用缓存实现相同查询条件的总记录数量在一定周期内无需重复查询 sqltoy的分页取总记录的过程不是简单的select count(1) from (原始sql);而是智能判断是否变成:select count(1) from 'from后语句', 并自动剔除最外层的order by sqltoy支持并行查询:parallel="true",同时查询总记录数和单页数据,大幅提升性能 在极特殊情况下sqltoy分页考虑是最优化的,如:with t1 as (),t2 as @fast(select * from table1) select * from xxx 这种复杂查询的分页的处理,sqltoy的count查询会是:with t1 as () select count(1) from table1, 如果是:with t1 as @fast(select * from table1) select * from t1 ,count sql 就是:select count(1) from table1 做过统计分析的您,害怕数据旋转吗?害怕同比环比吗? 无限极分组统计(含汇总求平均),算法配置简单又跨数据库! 同比环比 sqltoy还有什么? 因为篇幅原因,这里不过多展开,我相信您想要的,在sqltoy中基本都可以找到满意的答案!比如:分库分表、树形数据处理、sql跨数据库等等! 致谢 感谢广大网友的支持,提出宝贵的反馈意见,sqltoy的一步步的成熟是大家直觉式的眼光和敢于试错的精神加入到sqltoy这个还处于发展中的小众框架用户群体中来,让我们一起来让其成熟发展服务于更多的用户!也祝愿sqltoy可以帮助到大家,愿大家可以工作生活平衡!

优秀的个人博客,低调大师

Mybatis从浅入深-Plus(IDEA版通俗易懂)

每一个成功者都有一个开始。勇于开始,才能找到成功的路。你好,我是梦阳辰!期待与你相遇! Mybatis从浅入深(IDEA版通俗易懂) 01.使用注解开发 引入:大家之前都学过面向对象编程,也学习过接口,但在真正的开发中,很多时候我们会选择面向接口编程 根本原因∶解耦,可拓展,提高复用,分层开发中,上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性更好 在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了; 而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。关于接口的理解 接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。-接口的本身反映了系统设计人员对系统的抽象理解。 接口应有两类: 第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class); 第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface) ; 一个体有可能有多个抽象面。抽象体与抽象面是有区别的。 三个面向的区别: 面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法. 面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现. 接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题.更多的体现就是对系统整体的架构 使用注解开发:它们映射的语句可以不用 XML 来配置,而可以使用 Java 注解来配置。比如,上面的 XML 示例可以被替换成如下的配置: packageorg.mybatis.example;publicinterfaceBlogMapper{ @Select("SELECT*FROMblogWHEREid=#{id}") BlogselectBlog(intid);} 使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。 选择何种方式来配置映射,以及认为是否应该要统一映射语句定义的形式,完全取决于你和你的团队。 换句话说,永远不要拘泥于一种方式,你可以很轻松的在基于注解和 XML 的语句映射方式间自由移植和切换。 1.注解在接口上实现 ** *接口操作user表*/publicinterfaceUserMapper{ @Select("select*fromuser") List<User>selectUser();} 2.需要在核心配置文件中绑定接口。 <!--绑定接口--> <mappers> <mapperclass="com.mengyangchen.dao.UserMapper"/> </mappers> 测试: @Test publicvoidtest(){ //1.获取SqlSession对象 SqlSessionsqlSession=MybatisUtils.getSqlSession(); //方式一:getMapper //2.执行sql,获取sql,面向接口编程,获取UserMapper接口(以前是实现接口的实现类,现在是配置文件) UserMappermapper=sqlSession.getMapper(UserMapper.class); List<User>userList=mapper.selectUser(); /*StringsqlId="com.mengyangchen.dao.UserDao"+"."+"selectUser"; List<User>userList=sqlSession.selectList(sqlId);*/ for(Useruser:userList){ System.out.println(user); } //3.关闭SqlSession sqlSession.close(); } 本质:反射机制实现 底层:动态代理。 Mybatis详细的执行流程 多debug,多看底层源码。 注解完成增删改查 接口: //方法存在多个参数,所有的参数前面必须加上@Param("id")注解,引用对象不需要写 @Select("select*fromuserwhereid=#{id}") UserselectUserById(@Param("id")intid); @Insert("insertintouser(id,name,pwd)values(#{id},#{name},#{password})") intinsertUser(Useruser); 测试: @Test publicvoidselectUserById(){ //1.获取SqlSession对象 SqlSessionsqlSession=MybatisUtils.getSqlSession(); //方式一:getMapper //2.执行sql,获取sql,面向接口编程,获取UserMapper接口(以前是实现接口的实现类,现在是配置文件) UserMappermapper=sqlSession.getMapper(UserMapper.class); Useruser=mapper.selectUserById(1); System.out.println(user); sqlSession.close(); } @Test publicvoidinsertUser(){ //1.获取SqlSession对象 SqlSessionsqlSession=MybatisUtils.getSqlSession(); //方式一:getMapper //2.执行sql,获取sql,面向接口编程,获取UserMapper接口(以前是实现接口的实现类,现在是配置文件) UserMappermapper=sqlSession.getMapper(UserMapper.class); intnum=mapper.insertUser(newUser(3,"meng","123456")); if(num>0){ System.out.println("插入成功!"); } sqlSession.commit(); sqlSession.close(); } #{},${}的区别#{}可以防止sql注入。 02.Lombok Lombok项目是一个Java库,它会自动插入您的编辑器和构建工具中,从而使您的Java更加生动有趣。永远不要再写另一个getter或equals方法,带有一个注释的您的类有一个功能全面的生成器,自动化您的日志记录变量等等。 Lombok是一款Java开发插件,使得Java开发者可以通过其定义的一些注解来消除业务工程中冗长和繁琐的代码,尤其对于简单的Java模型对象(POJO)。在开发环境中使用Lombok插件后,Java开发人员可以节省出重复构建,诸如hashCode和equals这样的方法以及各种业务对象模型的accessor和ToString等方法的大量时间。对于这些方法,它能够在编译源代码期间自动帮我们生成这些方法,并没有如反射那样降低程序的性能。 使用步骤:1.在idea中安装Lombok插件 2.在项目中导入Lombokjar包 <!--https://mvnrepository.com/artifact/org.projectlombok/lombok--><dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>provided</scope></dependency> Lombok含有的注解: @Getterand@Setter@FieldNameConstants@ToString@EqualsAndHashCode@AllArgsConstructor,@RequiredArgsConstructorand@NoArgsConstructor@Log,@Log4j,@Log4j2,@Slf4j,@XSlf4j,@CommonsLog,@JBossLog,@Flogger,@CustomLog@Data@Builder@SuperBuilder@Singular@Delegate@Value@Accessors@Wither@With@SneakyThrows@val@var 结果: importlombok.Data;@DatapublicclassUser{ privateIntegerid; privateStringname; privateStringpassword; } 自动帮我们写了getter或equals等方法。 @Data:无参构造,get,set,toString,hashcode,equals 无参和所有参数:注意:了解即可。 03.多对一处理 多个学生,对应一个老师。对于学生而言:关联…多个学生关联一个老师(多对一) 对于老师而言:集合 一个老师,有很多学生(一对多) 多对一:实体类 publicclassStudent{ privateIntegerid; privateStringname; //学生需要关联一个老师 privateTeacherteacher; publicIntegergetId(){ returnid; } publicvoidsetId(Integerid){ this.id=id; } publicStringgetName(){ returnname; } publicvoidsetName(Stringname){ this.name=name; } publicTeachergetTeacher(){ returnteacher; } publicvoidsetTeacher(Teacherteacher){ this.teacher=teacher; } @Override publicStringtoString(){ return"Student{"+ "id="+id+ ",name='"+name+'\''+ ",teacher="+teacher+ '}'; }} publicclassTeacher{ privateIntegerid; privateStringname; publicIntegergetId(){ returnid; } publicvoidsetId(Integerid){ this.id=id; } publicStringgetName(){ returnname; } publicvoidsetName(Stringname){ this.name=name; } @Override publicStringtoString(){ return"Teacher{"+ "id="+id+ ",name='"+name+'\''+ '}'; }} 环境搭建:1.新建实体类Teacher,Student2.建立Mapper接口3.建立Mapper.xml文件4.在核心配置文件中绑定注册我们的mapper接口或者文件。5.测试是否成功。 publicinterfaceTeacherMapper{ @Select("select*fromteacherwhereid=#{tid}") TeacherselectTeacherById(@Param("tid")intid);} <mappers> <mapperclass="com.mengyangchen.dao.TeacherMapper"/> <mapperclass="com.mengyangchen.dao.StudentMapper"/></mappers> publicclassMyTest{ @Test publicvoidtest(){ SqlSessionsqlSession=MybatisUtils.getSqlSession(); TeacherMappermapper=sqlSession.getMapper(TeacherMapper.class); Teacherteacher=mapper.selectTeacherById(1); System.out.println(teacher); sqlSession.close(); }} 嵌套查询(按照查询嵌套处理)(子查询):select语句的嵌套。这里测试的时候出现异常:org.apache.ibatis.binding.bindingexception: invalid bound statement (not found) 问题出在:我在创建包的时候采用的是: com.mengyangchen.dao 改为一个一个的创建即可。 <?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEmapper PUBLIC"-//mybatis.org//DTDMapper3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--绑定一个对应的Dao/Mapper接口--><!--以前是写一个类实现Dao接口,现在绑定即可--><mappernamespace="com.mengyangchen.dao.StudentMapper"><!--sql语句嵌套思路:1.查询所有的学生信息2.根据查询出来的学生的tid,寻找对应的老师--> <resultMapid="studentTeacher"type="student"> <resultproperty="id"column="id"/> <resultproperty="name"column="name"/> <!--复杂的属性,我们需要单独处理对象association集合collection--> <associationproperty="teacher"column="tid"javaType="Teacher"select="selectTeacherById"/> </resultMap><selectid="selectStudentInfo"resultMap="studentTeacher"> select*fromstudent</select> <selectid="selectTeacherById"resultType="teacher"> select*fromteacherwhereid=#{id} </select></mapper> 结果: 联表查询(按照结果嵌套处理): <?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEmapper PUBLIC"-//mybatis.org//DTDMapper3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--绑定一个对应的Dao/Mapper接口--><!--以前是写一个类实现Dao接口,现在绑定即可--><mappernamespace="com.mengyangchen.dao.StudentMapper"><!--sql语句嵌套思路:1.查询所有的学生信息2.根据查询出来的学生的tid,寻找对应的老师--> <resultMapid="studentTeacher"type="student"> <resultproperty="id"column="id"/> <resultproperty="name"column="name"/> <!--复杂的属性,我们需要单独处理对象association集合collection--> <associationproperty="teacher"column="tid"javaType="Teacher"> <resultproperty="name"column="teacherName"/> </association> </resultMap><selectid="selectStudentInfo"resultMap="studentTeacher"> selects.idid,s.namename,t.nameteacherNamefromstudentsinnerjointeachertons.tid=t.id</select></mapper> 测试: @Test publicvoidstudentTest(){ SqlSessionsqlSession=MybatisUtils.getSqlSession(); StudentMappermapper=sqlSession.getMapper(StudentMapper.class); List<Student>list=mapper.selectStudentInfo(); for(Studentstudent:list){ System.out.println(student); } sqlSession.close(); } 04.一对多处理 一个老师对应多个学生对于老师而言就是一对多。实体类: publicclassTeacher{ privateIntegerid; privateStringname; //一个老师有多个学生 privateList<Student>student; publicIntegergetId(){ returnid; } publicvoidsetId(Integerid){ this.id=id; } publicStringgetName(){ returnname; } publicvoidsetName(Stringname){ this.name=name; } publicList<Student>getStudent(){ returnstudent; } publicvoidsetStudent(List<Student>student){ this.student=student; } @Override publicStringtoString(){ return"Teacher{"+ "id="+id+ ",name='"+name+'\''+ ",student="+student+ '}'; }} publicclassStudent{ privateIntegerid; privateStringname; privateIntegertid; publicIntegergetId(){ returnid; } publicvoidsetId(Integerid){ this.id=id; } publicStringgetName(){ returnname; } publicvoidsetName(Stringname){ this.name=name; } publicIntegergetTid(){ returntid; } publicvoidsetTid(Integertid){ this.tid=tid; } @Override publicStringtoString(){ return"Student{"+ "id="+id+ ",name='"+name+'\''+ ",tid="+tid+ '}'; }} 接口: publicinterfaceTeacherMapper{ TeacherselectTeacherById(@Param("tid")intid);} 配置文件: <?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEmapper PUBLIC"-//mybatis.org//DTDMapper3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--绑定一个对应的Dao/Mapper接口--><!--以前是写一个类实现Dao接口,现在绑定即可--><mappernamespace="com.mengyangchen.dao.TeacherMapper"> <!--查询语句--> <!--id相对于以前的书写,表示重写的方法名(以前在方法中执行连接数据库等操作,现在不需要了,只需要执行sql--> <!--resultType返回结果--> <!--按照结果嵌套查询--><selectid="selectTeacherById"resultMap="teacherStudent"> selects.idid,s.namename,t.nameteacherNamefromstudentsinnerjointeachertons.tid=t.id</select> <resultMapid="teacherStudent"type="teacher"> <resultproperty="name"column="teacherName"/> <collectionproperty="student"ofType="Student"> <resultproperty="id"column="id"/> <resultproperty="name"column="name"/> </collection> </resultMap></mapper> 05.动态sql 动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。 如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。 ifchoose(when,otherwise)trim(where,set)foreach 使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。比如: <selectid="findActiveBlogWithTitleLike" resultType="Blog"> SELECT*FROMBLOG WHEREstate=‘ACTIVE’<iftest="title!=null"> ANDtitlelike#{title} </if></select> 动态sql之if 实现根据不同条件查询数据! 实体类: packagecom.mengyangchen.pojo;importjava.util.Date;publicclassBlog{ privateStringid; privateStringtitle; privateStringauthor; privateDatecreateTime;//属性名和字段名不一致 privateIntegerviews; publicBlog(){ } publicStringgetId(){ returnid; } publicvoidsetId(Stringid){ this.id=id; } publicStringgetTitle(){ returntitle; } publicvoidsetTitle(Stringtitle){ this.title=title; } publicStringgetAuthor(){ returnauthor; } publicvoidsetAuthor(Stringauthor){ this.author=author; } publicDategetCreateTime(){ returncreateTime; } publicvoidsetCreateTime(DatecreateTime){ this.createTime=createTime; } publicIntegergetViews(){ returnviews; } publicvoidsetViews(Integerviews){ this.views=views; } @Override publicStringtoString(){ return"Blog{"+ "id="+id+ ",title='"+title+'\''+ ",author='"+author+'\''+ ",createTime="+createTime+ ",views="+views+ '}'; }} 接口: packagecom.mengyangchen.dao;importcom.mengyangchen.pojo.Blog;importjava.util.List;importjava.util.Map;publicinterfaceBlogMapper{ /*插入数据*/ intinsertBlog(Blogblog); /*查询博客*/ List<Blog>queryBlogIf(Mapmap);} 配置文件: <?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEmapper PUBLIC"-//mybatis.org//DTDMapper3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.mengyangchen.dao.BlogMapper"> <insertid="insertBlog"parameterType="blog"> insertintomybatis.blog(id,title,author,create_time,views)values(#{id},#{title},#{author},#{createTime},#{views}); </insert> <selectid="queryBlogIf"parameterType="map"resultType="blog"> select*frommybatis.blogwhere1=1 <iftest="title!=null"> andtitlelike"%"#{title}"%" </if> <iftest="author!=null"> andauthorlike"%"#{author}"%" </if> </select></mapper> 属性名和字段名不一致,一个是下划线,一个为驼峰。 <?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEconfiguration PUBLIC"-//mybatis.org//DTDConfig3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><!--核心配置文件--><configuration><!--引入外部配置文件--> <propertiesresource="db.properties"> <propertyname="username"value="root"/><!--一配置文件中为准--> <propertyname="password"value="123456"/> </properties> <!--标准日志实现--> <settings> <settingname="logImpl"value="STDOUT_LOGGING"/> <!--是否开启自动驼峰命名规则映射--> <settingname="mapUnderscoreToCamelCase"value="true"/> </settings> <!--别名--> <typeAliases> <packagename="com.mengyangchen.pojo"/> </typeAliases> <environmentsdefault="development"> <environmentid="development"> <!--事务管理--> <transactionManagertype="JDBC"/> <dataSourcetype="POOLED"> <propertyname="driver"value="${driver}"/><!--&amp是xml的转义字符(即为&)--> <propertyname="url"value="${url}"/> <propertyname="username"value="${username}"/> <propertyname="password"value="${password}"/> </dataSource> </environment> </environments><mappers> <mapperclass="com.mengyangchen.dao.BlogMapper"/></mappers></configuration> 动态sql之trim (where, set) 前面几个例子已经方便地解决了一个臭名昭著的动态 SQL 问题。现在回到之前的 “if” 示例,这次我们将 “state = ‘ACTIVE’” 设置成动态条件,看看会发生什么。 <selectid="findActiveBlogLike" resultType="Blog"> SELECT*FROMBLOG WHERE<iftest="state!=null"> state=#{state} </if> <iftest="title!=null"> ANDtitlelike#{title} </if> <iftest="author!=nullandauthor.name!=null"> ANDauthor_namelike#{author.name} </if></select> 如果没有匹配的条件会怎么样?最终这条 SQL 会变成这样: SELECT*FROMBLOG WHERE 这会导致查询失败。如果匹配的只是第二个条件又会怎样?这条 SQL 会是这样: SELECT*FROMBLOG WHERE ANDtitlelike‘someTitle’ 这个查询也会失败。这个问题不能简单地用条件元素来解决。这个问题是如此的难以解决,以至于解决过的人不会再想碰到这种问题。 MyBatis 有一个简单且适合大多数场景的解决办法。而在其他场景中,可以对其进行自定义以符合需求。而这,只需要一处简单的改动: <selectid="findActiveBlogLike" resultType="Blog"> SELECT*FROMBLOG<where> <iftest="state!=null"> state=#{state} </if> <iftest="title!=null"> ANDtitlelike#{title} </if> <iftest="author!=nullandauthor.name!=null"> ANDauthor_namelike#{author.name} </if> </where></select> where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。上个例子改完后: <?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEmapper PUBLIC"-//mybatis.org//DTDMapper3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.mengyangchen.dao.BlogMapper"> <insertid="insertBlog"parameterType="blog"> insertintomybatis.blog(id,title,author,create_time,views)values(#{id},#{title},#{author},#{createTime},#{views}); </insert> <selectid="queryBlogIf"parameterType="map"resultType="blog"> select*frommybatis.blog<where> <iftest="title!=null"> titlelike"%"#{title}"%" </if> <iftest="author!=null"> andauthorlike"%"#{author}"%" </if> </where> </select> </mapper> 如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为: <trimprefix="WHERE"prefixOverrides="AND|OR"> ...</trim> prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。 用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如: 解决了最后一个条件不需要,的问题。 <updateid="updateAuthorIfNecessary"> updateAuthor<set> <iftest="username!=null">username=#{username},</if> <iftest="password!=null">password=#{password},</if> <iftest="email!=null">email=#{email},</if> <iftest="bio!=null">bio=#{bio}</if> </set> whereid=#{id}</update> 这个例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。 来看看与 set 元素等价的自定义 trim 元素吧: <trimprefix="SET"suffixOverrides=","> ...</trim> 动态sql之choose (when, otherwise) 有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。还是上面的例子,但是策略变为:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG <selectid="findActiveBlogLike" resultType="Blog"> SELECT*FROMBLOGWHEREstate=‘ACTIVE’<choose> <whentest="title!=null"> ANDtitlelike#{title} </when> <whentest="author!=nullandauthor.name!=null"> ANDauthor_namelike#{author.name} </when> <otherwise> ANDfeatured=1 </otherwise> </choose></select> 与if的区别只会执行一个条件。练习: <selectid="queryBlogChoose"parameterType="map"resultType="blog"> select*fromblog<where> <choose> <whentest="title!=null"> title=#{title} </when> <whentest="author!=null"> andauthor=#{author} </when> <otherwise> andviews=#{views} </otherwise> </choose> </where> </select> @Test publicvoidqueryBlogChoose(){ SqlSessionsqlSession=MybatisUtils.getSqlSession(); BlogMappermapper=sqlSession.getMapper(BlogMapper.class); Mapmap=newHashMap(); map.put("title","Mybatis你好!"); map.put("author","梦阳辰"); List<Blog>list=mapper.queryBlogChoose(map); for(Blogblog:list){ System.out.println(blog); } } 动态sql之foreach 06.sql片段 将一些通用的sql片段提取出来。实现sql代码的复用。 07.缓存 1.什么是缓存?存在内存中的临时数据。将用户经常查询的数据放在缓存((内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。 2.为什么使用缓存?减少和数据库的交互次数,减少系统开销,提高系统效率。 3.什么样的数据能使用缓存?经常查询并且不经常改变的数据。Mybatis缓存 MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。 MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)。 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存 一级缓存 MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。 为了使它更加强大而且易于配置,我们对 MyBatis 3 中的缓存实现进行了许多改进。默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 一级缓存也叫本地缓存:SqlSession 与数据库同一次会话期间查询到的数据会放在本地缓存中。以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库; 测试步骤:1.开启日志! 2.测试在一个Sesion中查询两次相同记录 3.查看日志输出 映射语句文件中的所有 select 语句的结果将会被缓存。映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。缓存不会定时进行刷新(也就是说,没有刷新间隔)。缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。 缓存失效的情况:1.查询不同的内容 2.增删改操作,可能会改变原来的数据,所以会刷新缓存。 3.查询不同的Mapper.xml 4.手动清除缓存。 sqlSession.clearCache();//手动清理缓存 一级缓存存在于sqlsession获得到关闭,默认开启(有效期在获得连接到关闭连接)。 二级缓存 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存· 基于namespace级别的缓存,一个名称空间,对应一个二级缓存; 工作机制一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中; 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中; 新的会话查询信息,就可以从二级缓存中获取内容; 不同的mapper查出的数据会放在自己对应的缓存(map)中; 默认情况下,只启用了本地的会话缓存(一级缓存),它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行: <cache/> 缓存只作用于 cache 标签所在的映射文件中的语句。如果你混合使用 Java API 和 XML 映射文件,在共用接口中的语句将不会被默认缓存。你需要使用 @CacheNamespaceRef 注解指定缓存作用域。 这些属性可以通过 cache 元素的属性来修改。比如: <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/> 这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。 可用的清除策略有: LRU – 最近最少使用:移除最长时间不被使用的对象。FIFO – 先进先出:按对象进入缓存的顺序来移除它们。SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。默认的清除策略是 LRU。 步骤:1.开启全局缓存(默认开启)。2.在要使用二级缓存的Mapper中开启3.问题:我们需要将实体类序列化!否则会报错。 implementsSerializable 只要开启了二级缓存,在同一个Mapper下就有效。 所有的数据都会先放在一级缓存中。 只有当会话提交,或者关闭的时候,才会提交到二级缓存中! 缓存的原理 自定义缓存 EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。1.导包 第三方缓存<!--https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache--><dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.1.0</version></dependency> 除了上述自定义缓存的方式,你也可以通过实现你自己的缓存,或为其他第三方缓存方案创建适配器,来完全覆盖缓存行为。 <cachetype="com.domain.something.MyCustomCache"/> 这个示例展示了如何使用一个自定义的缓存实现。type 属性指定的类必须实现 org.apache.ibatis.cache.Cache 接口,且提供一个接受 String 参数作为 id 的构造器。 这个接口是 MyBatis 框架中许多复杂的接口之一,但是行为却非常简单。 publicinterfaceCache{ StringgetId(); intgetSize(); voidputObject(Objectkey,Objectvalue); ObjectgetObject(Objectkey); booleanhasKey(Objectkey); ObjectremoveObject(Objectkey); voidclear();} 放假回家已经好几天啦,感觉要学习的东西还很多。加油,下一篇spring见!

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册