关于mybatis:MyBatisPlus-效能提升秘籍掌握这些注解事半功倍

MyBatis-Plus是一个功能强大的MyBatis扩大插件,它提供了许多便捷的注解,让咱们在开发过程中可能更加高效地实现数据库操作,本文将带你一一理解这些注解,并通过实例来展现它们的魅力。 一、@Tablename注解这个注解用于指定实体类对应的数据库表名。如果你的表名和实体类名不统一,就须要用到它: @TableName("user_info")public class UserInfo { // 类的属性和办法}在上述代码中,即便实体类名为UserInfo,但通过@TableName注解,咱们晓得它对应数据库中的"user_info"表。 二、@Tableld注解每个数据库表都有主键,@TableId注解用于标识实体类中的主键属性。通常与@TableName配合应用,确保主键映射正确。 AUTO(0),NONE(1),INPUT(2),ASSIGN_ID(3),ASSIGN_UUID(4),/** @deprecated */@DeprecatedID_WORKER(3),/** @deprecated */@DeprecatedID_WORKER_STR(3),/** @deprecated */@DeprecatedUUID(4); INPUT 如果开发者没有手动赋值,则数据库通过自增的形式给主键赋值,如果开发者手动赋值,则存入该值。AUTO 默认就是数据库自增,开发者无需赋值。ASSIGN_ID MP 主动赋值,雪花算法。ASSIGN_UUID 主键的数据类型必须是 String,主动生成 UUID 进行赋值。 // 本人赋值 //@TableId(type = IdType.INPUT) // 默认应用的雪花算法,长度比拟长,所以应用Long类型,不必本人赋值 @TableId private Long id;测试@Test void save(){ // 因为id加的有注解,这里就不必赋值了 Student student = new Student(); student.setName("天明"); student.setAge(18); mapper.insert(student);} 雪花算法雪花算法是由Twitter颁布的分布式主键生成算法,它可能保障不同表的主键的不重复性,以及雷同表的主键的有序性。 核心思想: 长度共64bit(一个long型)。首先是一个符号位,1bit标识,因为long根本类型在Java中是带符号的,最高位是符号位,负数是0,正数是1,所以id个别是负数,最高位是0。41bit工夫截(毫秒级),存储的是工夫截的差值(以后工夫截 - 开始工夫截),后果约等于69.73年。10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID,能够部署在1024个节点)。12bit作为毫秒内的流水号(意味着每个节点在每毫秒能够产生 4096 个 ID)。 长处: 整体上依照工夫自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率较高。 三、@TableField注解当你的实体类属性名与数据库字段名不统一时,@TableField注解能够帮忙你建设二者之间的映射关系。 映射非主键字段,value 映射字段名;exist 示意是否为数据库字段 false,如果实体类中的成员变量在数据库中没有对应的字段,则能够应用 exist,VO、DTO;select 示意是否查问该字段;fill 示意是否主动填充,将对象存入数据库的时候,由 MyBatis Plus 主动给某些字段赋值,create_time、update_time。 主动填充1)给表增加 create_time、update_time 字段。 ...

February 28, 2024 · 2 min · jiezi

关于mybatis:MyBatisPlus快速入门指南零基础学习也能轻松上手

在Java开发的世界里,长久层框架的抉择对于我的项目的胜利至关重要。明天,咱们要聊的配角是MyBatis-Plus——一个增强版的MyBatis,它以其弱小的性能、简洁的代码和高效的性能,正在成为越来越多开发者的新宠。那么,MyBatis-Plus到底是什么?又该如何疾速入门呢?让咱们一起摸索这个弱小的工具。 一、MyBatis-Plus简介1、简介MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的加强工具,在 MyBatis 的根底上只做加强不做扭转,为简化开发、提高效率而生。 2、个性无侵入: 只做加强不做扭转,引入它不会对现有工程产生影响,如丝般顺滑。损耗小: 启动即会主动注入根本 CURD,性能根本无损耗,间接面向对象操作,BaseMapper。弱小的 CRUD 操作: 内置通用 Mapper、通用 Service,仅仅通过大量配置即可实现单表大部分 CRUD 操作,更有弱小的条件结构器,满足各类应用需要,简略的CRUD操作不必本人编写。反对 Lambda 模式调用: 通过 Lambda 表达式,不便的编写各类查问条件,无需再放心字段写错。反对主键主动生成: 反对多达 4 种主键策略(内含分布式惟一 ID 生成器 - Sequence),可自在配置,完满解决主键问题。反对 ActiveRecord 模式: 反对 ActiveRecord 模式调用,实体类只需继承 Model 类即可进行弱小的 CRUD 操作。反对自定义全局通用操作: 反对全局通用办法注入( Write once, use anywhere )。内置代码生成器: 采纳代码或者 Maven 插件可疾速生成 Mapper 、 Model 、 Service 、 Controller 层代码,反对模板引擎,更有超多自定义配置等您来应用(主动生成代码)。内置分页插件: 基于 MyBatis 物理分页,开发者无需关怀具体操作,配置好插件之后,写分页等同于一般 List 查问。分页插件反对多种数据库: 反对 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库。内置性能剖析插件: 可输入 SQL 语句以及其执行工夫,倡议开发测试时启用该性能,能疾速揪出慢查问。内置全局拦挡插件: 提供全表 delete 、 update 操作智能剖析阻断,也可自定义拦挡规定,预防误操作。 3、框架结构 二、疾速入门1.开发环境2.创立数据库和表1)创立表单 CREATE DATABASE `mp_study` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;use `mp_study`;CREATE TABLE `user` (`id` bigint(20) NOT NULL COMMENT '主键ID',`name` varchar(30) DEFAULT NULL COMMENT '姓名',`age` int(11) DEFAULT NULL COMMENT '年龄',`email` varchar(50) DEFAULT NULL COMMENT '邮箱',PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;2)增加数据 ...

February 26, 2024 · 3 min · jiezi

关于mybatis:聊聊mybatis的Interceptor机制

序本文次要钻研一下mybatis的Interceptor机制 Interceptororg/apache/ibatis/plugin/Interceptor.java public interface Interceptor { Object intercept(Invocation invocation) throws Throwable; default Object plugin(Object target) { return Plugin.wrap(target, this); } default void setProperties(Properties properties) { // NOP }}Interceptor定义了intercept办法,其参数为Invocation类型,同时默认提供了plugin办法,通过Plugin.wrap(target, this)进行包装Invocationorg/apache/ibatis/plugin/Invocation.java public class Invocation { private final Object target; private final Method method; private final Object[] args; public Invocation(Object target, Method method, Object[] args) { this.target = target; this.method = method; this.args = args; } public Object getTarget() { return target; } public Method getMethod() { return method; } public Object[] getArgs() { return args; } public Object proceed() throws InvocationTargetException, IllegalAccessException { return method.invoke(target, args); }}Invocation定义了target、method、args属性,提供了proceed办法则是反射执行method办法Pluginorg/apache/ibatis/plugin/Plugin.java ...

August 30, 2023 · 4 min · jiezi

关于mybatis:mybatis的MappedStatement是线程安全的吗

序本文次要钻研一下mybatis MappedStatement MappedStatementorg/apache/ibatis/mapping/MappedStatement.java public final class MappedStatement { private String resource; private Configuration configuration; private String id; private Integer fetchSize; private Integer timeout; private StatementType statementType; private ResultSetType resultSetType; private SqlSource sqlSource; private Cache cache; private ParameterMap parameterMap; private List<ResultMap> resultMaps; private boolean flushCacheRequired; private boolean useCache; private boolean resultOrdered; private SqlCommandType sqlCommandType; private KeyGenerator keyGenerator; private String[] keyProperties; private String[] keyColumns; private boolean hasNestedResultMaps; private String databaseId; private Log statementLog; private LanguageDriver lang; private String[] resultSets; private boolean dirtySelect; //......} MappedStatement定义了SqlSourceMappedStatement.Builder public static class Builder { private final MappedStatement mappedStatement = new MappedStatement(); public Builder(Configuration configuration, String id, SqlSource sqlSource, SqlCommandType sqlCommandType) { mappedStatement.configuration = configuration; mappedStatement.id = id; mappedStatement.sqlSource = sqlSource; mappedStatement.statementType = StatementType.PREPARED; mappedStatement.resultSetType = ResultSetType.DEFAULT; mappedStatement.parameterMap = new ParameterMap.Builder(configuration, "defaultParameterMap", null, new ArrayList<>()).build(); mappedStatement.resultMaps = new ArrayList<>(); mappedStatement.sqlCommandType = sqlCommandType; mappedStatement.keyGenerator = configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType) ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE; String logId = id; if (configuration.getLogPrefix() != null) { logId = configuration.getLogPrefix() + id; } mappedStatement.statementLog = LogFactory.getLog(logId); mappedStatement.lang = configuration.getDefaultScriptingLanguageInstance(); } //...... } MappedStatement定义了一个Builder用于结构MappedStatementMapperBuilderAssistantorg/apache/ibatis/builder/MapperBuilderAssistant.java ...

August 29, 2023 · 3 min · jiezi

关于mybatis:聊聊mybatis的ParamNameResolver

序在mybatis的interceptor获取MapperMethod.ParamMap这种参数类型时,常常会多出param1,param2,collection,list,array这些参数,这些不是接口本人定义的,而是ParamNameResolver主动增加的 ParamNameResolverorg/apache/ibatis/reflection/ParamNameResolver.java public class ParamNameResolver { public static final String GENERIC_NAME_PREFIX = "param"; /** * <p> * A single non-special parameter is returned without a name. * Multiple parameters are named using the naming rule. * In addition to the default names, this method also adds the generic names (param1, param2, * ...). * </p> * * @param args * the args * @return the named params */ public Object getNamedParams(Object[] args) { final int paramCount = names.size(); if (args == null || paramCount == 0) { return null; } else if (!hasParamAnnotation && paramCount == 1) { Object value = args[names.firstKey()]; return wrapToMapIfCollection(value, useActualParamName ? names.get(0) : null); } else { final Map<String, Object> param = new ParamMap<>(); int i = 0; for (Map.Entry<Integer, String> entry : names.entrySet()) { param.put(entry.getValue(), args[entry.getKey()]); // add generic param names (param1, param2, ...) final String genericParamName = GENERIC_NAME_PREFIX + (i + 1); // ensure not to overwrite parameter named with @Param if (!names.containsValue(genericParamName)) { param.put(genericParamName, args[entry.getKey()]); } i++; } return param; } } //......}getNamedParams办法针对单个参数没有加@Param的场景会调用wrapToMapIfCollection,其余的则应用param1,param2这种,这里用了contains,也就是如果自身命名就有蕴含param1,param2这种则不会增加wrapToMapIfCollectionorg/apache/ibatis/reflection/ParamNameResolver.java ...

August 28, 2023 · 2 min · jiezi

关于mybatis:MybatisSQL分析组件-京东云技术团队

背景大促备战,最大的隐患项之一就是慢sql,带来的破坏性最大,也是日常工作中常常带来整个利用抖动的最大隐患,而且对sql好坏的评估有肯定的技术要求,有一些缺乏经验或者因为不够认真造成一个坏的sql胜利走到了线上,等发现的时候要么是造成了线上影响、报警、或者后置的慢sql采集发现,这时候个别无奈疾速止损,须要批改代码上线、或者调整数据库索引。 外围痛点: 1、无奈提前发现慢sql,可能好转为慢sql的语句 2、线上呈现慢sql后,无奈疾速止损 解决思路1、把问题解决在上线之前,最好的方法就是在测试阶段,甚至在开发阶段就发现一个sql的好坏 2、线上发现慢sql后除了改代码上线、调整数据库表索引的形式外,反对热更新的形式替换sql语句。 部门外部,目前大部分数据库框架采纳的mybatis,而后基于mybatis自身的实现机制中,开发一个mybatis组件,能够主动对运行的sql进行提取和剖析,定制一套默认的剖析规定,让sql在开发环境和测试环境执行的时候,就可能做初步的评估,把有问题的慢sql在这个阶段裸露进去;同时具备sql替换性能,在线上呈现问题sql的时候,能够通过ducc配置疾速实现对一个sql的在线替换,大大降低线上问题的止损工夫。 开源计划调研目前,支流的sql剖析组件,外围性能次要放在了两个方向:1、慢sql的剖析和优化倡议 2、sql的优化重写性能,而且次要偏运维的辅助性能无奈做到无侵入的和利用代码进行集成。也就无奈实现咱们的外围痛点,慢sql提前剖析预警和动静sql替换。 []() 设计方案外围性能:SQL剖析预警能力、SQL替换能力 []() 具体设计次要分为8个功能模块 模块一:core 次要负责组件的接入到mybatis,以及其它模块的编排调用 模块二:config 次要负责组件配置信息的初始化 模块三:extrat 次要通过解析mybatis 相干对象,提取残缺的待执行sql 模块四:analysis 次要拼接剖析语句,执行explain剖析语句并获取剖析后果 模块五:rule sql剖析规定的加载和初始化,反对自定义规定 目前默认规定(继续扩大): 1、查问未匹配索引 2、匹配索引过滤成果较差 3、返回行数过多 4、应用了文件排序 模块六:score 基于剖析后果和配置的评分规定进行匹配打分,优化倡议组装 模块七:out 输出模块,对于输入后果进行输入,目前已error日志、MQ两种输入形式 模块八:replace替换模块,能够对sql语句基于ducc配置进行动静替换 应用办法1、引入依赖jar包<dependency> <groupId>com.jd.sql.analysis</groupId> <artifactId>sql-analysis</artifactId> <version>1.2-SNAPSHOT</version></dependency>2、配置组件xml<configuration> <plugins> <plugin interceptor="com.jd.sql.analysis.core.SqlAnalysisAspect" > <!-- 开启sql剖析性能最简配置 --> <property name="analysisSwitch" value="true"/> <!-- 开启sql替换性能最简配置 --> <property name="sqlReplaceModelSwitch" value="true"/> <property name="duccAppName" value="workbench-backend"/> <property name="duccUri" value="ucc://workbench-backend:2d6991cb865f4e6bac6c3e1cf7794cdf@test.ducc.jd.local/v1/namespace/workbench_backend/config/default/profiles/test?longPolling=60000&necessary=false"/> <property name="duccMonitorKey" value="refundBugFlag"/> </plugin> </plugins></configuration>3、外围配置项属性用处是否必填默认值备注analysisSwitch是否开启剖析性能是falseonlyCheckOnce是否对一个sqlid只剖析一次非truecheckInterval每个sqlid剖析距离非300000毫秒onlyCheckOnce 为false才失效exceptSqlIds须要过滤不剖析的sqlid非sqlType剖析的sql类型非默认select、update反对scoreRuleLoadClass评分规定加载器,用于扩大自定义规定非outModel默认输入形式非默认值:LOG反对LOG、MQ两种形式outputClass评分后果输入类,用于扩大自定义后果输入形式非sqlReplaceModelSwitchsql替换模块是否开启非默认 falseduccAppNameducc配置的利用名称(jdos)非duccUriducc uri配置非duccMonitorKeysql替换配置文件对应的key非4、默认剖析成果展现4.1、慢sql剖析成果[]() 4.2、sql动静替换成果5、实际应用计划5.1、慢sql剖析-日志输入+关键词告警<configuration> <plugins> <plugin interceptor="com.jd.sql.analysis.core.SqlAnalysisAspect" > <property name="analysisSwitch" value="true"/> </plugin> </plugins></configuration>5.2、慢sql剖析-日志输入+mq输入+es存储+Kibana剖析<configuration> <plugins> <plugin interceptor="com.jd.sql.analysis.core.SqlAnalysisAspect" > <property name="appName" value="workbench-backend"/> <property name="analysisSwitch" value="true"/> <property name="outputModel" value="mq"/> <property name="mqApp" value="qlstation"/> <property name="mqUser" value="qlstation"/> <property name="mqPassword" value="D1BCC547"/> <property name="mqAddress" value="jmq-testcluster.jd.local:50088"/> <property name="mqTopic" value="jdl_kds_key_node_log"/> </plugin> </plugins></configuration>最终成果 ...

July 6, 2023 · 1 min · jiezi

关于mybatis:Mybatis的parameterType造成线程阻塞问题分析-京东云技术团队

一、前言最近在新公布某个我的项目上线时,每次重启都会收到机器的 CPU 使用率告警,查看对应监控,继续时长达 5 分钟,对于服务重启有很大危险。而该我的项目有十分多 Consumer 生产,服务启动后会有大量线程去拉取音讯解决逻辑,通过屡次 Jstack 输入线程快照发现有很多 BLOCKED 状态线程,此文次要记录剖析 BLOCKED 起因。 二、剖析过程2.1、初步剖析"consumer_order_status_jmq1714_1684822992337" #3125 daemon prio=5 os_prio=0 tid=0x00007fd9eca34000 nid=0x1ca4f waiting for monitor entry [0x00007fd1f33b5000] java.lang.Thread.State: BLOCKED (on object monitor) at java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1027) - waiting to lock <0x000000056e822bc8> (a java.util.concurrent.ConcurrentHashMap$Node) at java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:1006) at org.apache.ibatis.type.TypeHandlerRegistry.getJdbcHandlerMap(TypeHandlerRegistry.java:234) at org.apache.ibatis.type.TypeHandlerRegistry.getTypeHandler(TypeHandlerRegistry.java:200) at org.apache.ibatis.type.TypeHandlerRegistry.getTypeHandler(TypeHandlerRegistry.java:191) at org.apache.ibatis.mapping.ParameterMapping$Builder.resolveTypeHandler(ParameterMapping.java:128) at org.apache.ibatis.mapping.ParameterMapping$Builder.build(ParameterMapping.java:103) at org.apache.ibatis.builder.SqlSourceBuilder$ParameterMappingTokenHandler.buildParameterMapping(SqlSourceBuilder.java:123) at org.apache.ibatis.builder.SqlSourceBuilder$ParameterMappingTokenHandler.handleToken(SqlSourceBuilder.java:67) at org.apache.ibatis.parsing.GenericTokenParser.parse(GenericTokenParser.java:78) at org.apache.ibatis.builder.SqlSourceBuilder.parse(SqlSourceBuilder.java:45) at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:44) at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:292) at com.github.pagehelper.PageInterceptor.intercept(PageInterceptor.java:83) at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61) at com.sun.proxy.$Proxy232.query(Unknown Source) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:77) at sun.reflect.GeneratedMethodAccessor160.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433) at com.sun.proxy.$Proxy124.selectOne(Unknown Source) at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:166) at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:82) at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59) ......通过对服务间断距离 1 分钟应用 Jstack 抓取线程快照,发现存在局部线程是 BLOCKED 状态,通过堆栈能够看出,以后线程阻塞在 ConcurrentHashMap.putVal,而 putVal 办法外部应用了 synchronized 导致以后线程被 BLOCKED,而上一级是 Mybaits 的TypeHandlerRegistry,TypeHandlerRegistry 的作用是记录 Java 类型与 JDBC 类型的互相映射关系,例如 java.lang.String 能够映射 JdbcType.CHAR、JdbcType.VARCHAR 等,更上一级是 Mybaits 的 ParameterMapping,而 ParameterMapping 的作用是记录申请参数的信息,包含 Java 类型、JDBC 类型,以及两种类型转换的操作类 TypeHandler。通过以上信息能够初步定位为在并发状况下 Mybaits 解析某些参数导致大量线程被阻塞,还需持续往下剖析。 ...

June 8, 2023 · 3 min · jiezi

关于mybatis:mybatis的缓存机制

前言最近在应用mybatis的时候发现了一个问题:当我进行更新操作时,通过id查问条件查出一个User对象,并批改user的姓名,在进行update函数前,通过切面去记录他的变更信息到变更记录表中。 public User update(User user) { User oldUser = new User(); oldUser.setId(user.getId()); oldUser = this.daoSupport.selectOne(oldUser); oldUser.setName(user.getName()); return this.daoSupport.update(oldUser);}在切面中,通过这个对象的主键去数据库查问到变更前的的值,和变更后的值做比照,不雷同的属性即为理论变更的属性。然而发现,在切面里通过主键查问进去的对象的各个属性值为变更后的值,这明明是在update之前的切面,变更内容并没有保留到数据库中,为何查问进去的值为变更后的值呢?为了排除切面的影响,我在查问并批改user的姓名后,在update语句前,再次查问user。 public User update(User user) { User oldUser = new User(); oldUser.setId(user.getId()); oldUser = this.daoSupport.selectOne(oldUser); oldUser.setName(user.getName()); User oldUser1 = new User(); oldUser1.setId(user.getId()); oldUser1 = this.daoSupport.selectOne(oldUser1); return this.daoSupport.update(oldUser);}此时,也的确是变更后的值,并且通过断点发现两个user为同一个对象,也就是说对象指针地址一样,那必定是变更后的值。猜想是存在着一种缓存机制,使得第二次查问应用了第一次查问的后果,然而这个后果是一个对象指针。 MyBatis缓存再网上查问得悉,mybatis的确有一种缓存机制,并且分为一级缓存和二级缓存。 在理解一级缓存前,先理解一下mybatis的SqlSession。在mybatis的根底写法中,咱们都是先获取SqlSession,而后通过SqlSession再去进行我的定义的mapper操作,当然DaoSupport定义了一些根本mapper操作且不须要手动定义SqlSession,然而实质上也是通过SqlSession对数据库进行操作。 通过浏览源码得悉,mybatis的一级缓存,就是在一个SqlSession的生命周期内,在进行一次查问时,将查问后果和查问条件存起来,在进行下一次查问时,先去匹配查问条件,若查问条件雷同,便不在去查询数据库,而是将上一次的查问后果返回,当然这里返回的是对象指针。那么就不难理解呈现的问题了。 解决解决很好解决。一种办法是全局敞开缓存,设置 mybatis.configuration.local-cache-scope=statement 一种办法时是第二次查问前清空缓存。 SqlSession sqlSession = SqlSessionUtils.getSqlSession(sqlSessionFactory);sqlSession.clearCache();其中sqlSessionFactory时通过依赖注入的。 源码浏览对于具体机制浏览,举荐两篇文章【不懂就问】MyBatis的一级缓存居然还会引来麻烦?聊聊MyBatis缓存机制(另外举荐一下美团技术团队的文章,写的都很好,大家能够浏览一下,下面的第二篇文章和上次的雪花算法都来自于那里。美团技术团队)

April 2, 2023 · 1 min · jiezi

关于mybatis:三天吃透mybatis面试八股文

本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址:https://github.com/Tyson0314/Java-learning Mybatis是什么?MyBatis框架是一个开源的数据长久层框架。它的外部封装了通过JDBC拜访数据库的操作,反对一般的SQL查问、存储过程和高级映射,简直打消了所有的JDBC代码和参数的手工设置以及后果集的检索。MyBatis作为长久层框架,其次要思维是将程序中的大量SQL语句剥离进去,配置在配置文件当中,实现SQL的灵便配置。这样做的益处是将SQL与程序代码拆散,能够在不批改代码的状况下,间接在配置文件当中批改SQL。ORM是什么ORM(Object Relational Mapping),对象关系映射,是一种为了解决关系型数据库数据与简略Java对象(POJO)的映射关系的技术。简略的说,ORM是通过应用形容对象和数据库之间映射的元数据,将程序中的对象主动长久化到关系型数据库中。 Mybatis和Hibernate的区别?次要有以下几点区别: Hibernate的开发难度大于MyBatis,次要因为Hibernate比较复杂,宏大,学习周期比拟长。Hibernate属于全自动ORM映射工具,应用Hibernate查问关联对象或者关联汇合对象时,能够依据对象关系模型间接获取,所以它是全自动的。而Mybatis在查问关联对象或关联汇合对象时,须要手动编写sql来实现,所以,称之为半自动ORM映射工具。数据库扩展性的区别。Hibernate与数据库具体的关联在XML中,所以HQL对具体是用什么数据库并不是很关怀。MyBatis因为所有sql都是依赖数据库书写的,所以扩展性、迁移性比拟差。缓存机制的区别。Hibernate的二级缓存配置在SessionFactory生成配置文件中进行具体配置,而后再在具体的表对象映射中配置那种缓存。MyBatis的二级缓存配置都是在每个具体的表对象映射中进行具体配置,这样针对不同的表能够自定义不同的缓冲机制,并且MyBatis能够在命名空间中共享雷同的缓存配置和实例,通过Cache-ref来实现。日志零碎欠缺性的区别。Hibernate日志零碎十分健全,波及宽泛,而Mybatis则除了根本记录性能外,性能单薄很多。sql的优化上,Mybatis要比Hibernate不便很多。因为Mybatis的sql都是写在xml里,因而优化sql比Hibernate不便很多。而Hibernate的sql很多都是主动生成的,无奈间接保护sql;总之写sql的灵便度上Hibernate不迭Mybatis。MyBatis框架的优缺点及其实用的场合长处 与JDBC相比,缩小了50%以上的代码量。MyBatis是易学的长久层框架,玲珑并且简略易学。MyBatis相当灵便,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML文件里,从程序代码中彻底拆散,升高耦合度,便于对立的治理和优化,并可重用。提供XML标签,反对编写动静的SQL,满足不同的业务需要。提供映射标签,反对对象与数据库的ORM字段关系映射。毛病 SQL语句的编写工作量较大,对开发人员编写SQL的能力有肯定的要求。SQL语句依赖于数据库,导致数据库不具备好的移植性,不能够轻易更换数据库。实用场景 MyBatis专一于SQL本身,是一个足够灵便的DAO层解决方案。对性能的要求很高,或者需要变动较多的我的项目,例如Web我的项目,那么MyBatis是不二的抉择。 Mybatis的工作原理读取MyBatis配置文件:mybatis-config.xml为MyBatis的全局配置文件,配置了MyBatis的运行环境等信息,例如数据库连贯信息。加载映射文件。映射文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,须要在MyBatis配置文件mybatis-config.xml中加载。mybatis-config.xml文件能够加载多个映射文件,每个文件对应数据库中的一张表。结构会话工厂:通过MyBatis的环境等配置信息构建会话工厂SqlSessionFactory。创立会话对象:由会话工厂创立SqlSession对象,该对象中蕴含了执行SQL语句的所有办法。Executor执行器:MyBatis底层定义了一个Executor 接口来操作数据库,它将依据SqlSession传递的参数动静地生成须要执行的SQL语句,同时负责查问缓存的保护。MappedStatement 对象:在Executor接口的执行办法中有一个MappedStatement类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id、参数等信息。输出参数映射:输出参数类型能够是Map、List等汇合类型,也能够是根本数据类型和POJO类型。输出参数映射过程相似于 JDBC对preparedStatement对象设置参数的过程。输入后果映射:输入后果类型能够是Map、List等汇合类型,也能够是根本数据类型和POJO类型。输入后果映射过程相似于 JDBC对后果集的解析过程。Mybatis都有哪些Executor执行器?它们之间的区别是什么?Mybatis有三种根本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。 SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立即敞开Statement对象。 ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就应用,不存在就创立,用完后,不敞开Statement对象,而是搁置于Map<String, Statement>内,供下一次应用。简言之,就是重复使用Statement对象。 BatchExecutor:执行update(没有select,JDBC批处理不反对select),将所有sql都增加到批处理中(addBatch()),期待对立执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()结束后,期待逐个执行executeBatch()批处理。与JDBC批处理雷同。 作用范畴:Executor的这些特点,都严格限度在SqlSession生命周期范畴内。 MyBatis中接口绑定有几种实现形式?通过注解绑定,在接口的办法下面加上 @Select@Update等注解外面蕴含Sql语句来绑定(SQL语句比较简单的时候,举荐注解绑定)通过xml外面写SQL来绑定, 指定xml映射文件外面的namespace必须为接口的全路径名(SQL语句比较复杂的时候,举荐xml绑定)Mybatis 是如何进行分页的?Mybatis 应用 RowBounds 对象进行分页,它是针对 ResultSet 后果集执行的内存分页,而非物理分页,先把数据都查出来,而后再做分页。 能够在 sql 内间接书写带有物理分页的参数来实现物理分页性能,也能够应用分页插件来实现物理分页。 分页插件的基本原理是什么?分页插件的基本原理是应用 Mybatis 提供的插件接口,实现自定义插件,在插件的拦挡办法内拦挡待执行的 sql,而后重写 sql(SQL 拼接 limit),依据 dialect 方言,增加对应的物理分页语句和物理分页参数,用到了技术 JDK 动静代理,用到了责任链设计模式。 简述Mybatis的插件运行原理Mybatis仅能够编写针对 ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis应用JDK的动静代理,为须要拦挡的接口生成代理对象以实现接口办法拦挡性能,每当执行这4种接口对象的办法时,就会进入拦挡办法,具体就是InvocationHandler的invoke()办法,当然,只会拦挡那些你指定须要拦挡的办法。 .如何编写一个插件?编写插件:实现 Mybatis 的 Interceptor 接口并复写 intercept()办法,而后再给插件编写注解,指定要拦挡哪一个接口的哪些办法即可,最初在配置文件中配置你编写的插件。 .Mybatis 是否反对提早加载?Mybatis 仅反对 association 关联对象和 collection 关联汇合对象的提早加载,association 指的就是一对一,collection 指的就是一对多查问。在 Mybatis 配置文件中,能够配置是否启用提早加载lazyLoadingEnabled=true|false。 提早加载的基本原理是什么?提早加载的基本原理是,应用 CGLIB 创立指标对象的代理对象,当调用指标办法时,进入拦截器办法。 比方调用a.getB().getName(),拦截器 invoke()办法发现 a.getB()是 null 值,那么就会独自发送当时保留好的查问关联 B 对象的 sql,把 B 查问上来,而后调用a.setB(b),于是 a 的对象 b 属性就有值了,接着实现a.getB().getName()办法的调用。 ...

March 7, 2023 · 1 min · jiezi

关于mybatis:初见MyBatis的理解与认知-三

MyBatis上期讲了用MyBatis来解决硬编码问题,但其实在测试用例里还是有硬编码的问题。 List<Brand> brands = sqlSession.selectList("com.happyfan.mapper.BrandMapper.selectAll");//com.happyfan.mapper.BrandMapper.selectAll 仍然是字符串,锁死在代码里了。而咱们用mapper代理开发,就能解决这个硬编码问题。 mapper 代理定义一个与 SQL 映射文件同名的 Mapper 接口,并将 Mapper 接口和 SQL 映射文件搁置在同一目录下设置 SQL 映射文件的 namespace 属性为 Mapper 接口全限定名(就是类的全称,带包的要用 . 隔开)在 Mapper 接口中定义方法,办法名就是 SQL 映射文件中 sql 语句的 id ,并放弃参数类型和返回值类型统一编码 通过 SqlSession 的 getMapper 办法获取 Mapper 接口的代理对象调用对应办法实现 sql 执行1、定义一个与 SQL 映射文件同名的 Mapper 接口,并将 Mapper 接口和 SQL 映射文件搁置在同一目录下 相似这样: 留神,在resource包下创立的Directory命名要用分隔符 / 而不能用 . ,用 . 会产生一些奇怪的事件(他可能会认为这个Directory就叫做com.happyfan.mapper). 2、设置 SQL 映射文件的 namespace 属性为 Mapper 接口全限定名(就是类的全称,带包的要用 . 隔开) <mapper namespace="com.happyfan.mapper.BrandMapper">3、在 Mapper 接口中定义方法,办法名就是SQL映射文件中 sql 语句的 id,并放弃参数类型和返回值类型统一 ...

February 1, 2023 · 2 min · jiezi

关于mybatis:初见MyBatis的理解与认知-二

MyBatisMyBatis疾速入门上期说了MyBatis的益处,这期就来体验一下MyBatis到底是如何的简略。还是先举一个例子: 查问brand表中的所有数据 创立brand表,增加数据创立模块,导入坐标编写MyBatis外围配置文件编写SQL映射文件(替换连贯数据的信息来解决硬编码的问题)编码 定义POJO类加载外围配置文件,获取SqlSessionFactory对象获取SqlSession对象,执行SQL语句开释资源1、创立brand表,增加数据 create table brand( id int auto_increment primary key, brand_name varchar(20) null, company_name varchar(20) null, ordered int null, description varchar(100) null, status int null);insert into brand (brand_name, company_name, ordered, description, status) values ('菠萝','菠萝手机',100,'XX有苹果,XX有菠萝,菠萝手机',1);insert into brand (brand_name, company_name, ordered, description, status) values ('泡面','康帅傅泡面',50,'美味重量超满足',1);2、创立模块,导入坐标官网文档有具体的创立模块,导入坐标的具体方法。官网文档:https://mybatis.org/mybatis-3... 如果应用 Maven 来构建我的项目,只有将上面的依赖代码置于 pom.xml 文件中即可: <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>x.x.x</version></dependency>当然咱们还须要连贯数据库,还须要MySQL驱动。须要测试还须要导入junit等等。 <dependency> <!--mybatis 依赖--> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.11</version></dependency><!--mysql 驱动--><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.30</version></dependency><!--junit 单元测试--><dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope></dependency><!-- 增加slf4j日志api --><dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.20</version></dependency><!-- 增加logback-classic依赖 --><dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version></dependency><!-- 增加logback-core依赖 --><dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version></dependency>除此之外,还须要一个logback的配置文件须要放入resources下边。对于logback配置文件参考官网文档:官网文档:https://logback.qos.ch/manual...实现之后,第二步创立模块导入坐标就准备就绪了,开始第三步。 ...

January 31, 2023 · 2 min · jiezi

关于mybatis:初见Mybatis的理解与认知-一

MyBatis什么是MyBatis?MyBatis是一款优良的长久层(负责将数据保留到数据库的那一层代码)框架(半成品,感觉和自热饭差不多),是用于简化JDBC开发的。MyBatis本是Apache的一个开源我的项目iBatis,2010年这个我的项目由apache software foundation 迁徙到了Google code,并改名为MyBatis。2013年11月迁徙到Github。一个新事物的呈现阐明这个新事物肯定领有旧事物没有的、不可比较的优越性,MyBatis亦是如此。 JDBC的毛病首先咱们先举一个简略JDBC的例子。 //注册驱动Class.forName("com.mysql.jdbc.Driver");//获取链接String url = "jdbc:mysql:///db1?useSSl=false;String username = "root";//数据库用户名称String password = "1234";//数据库明码Connection conn = DriverManager.getConnection(url,username,password);//接管输出的查问条件String gender = "男";//定义sqlString sql = "select * from user where gender = ?"//获取pstmt对象PreparedStatement pstmt = conn.prepareStatement(sql);//设置?的值pstmt.setString(1,gender);//执行sqlResultSet rs = pstmt.executeQuery();//遍历Result,获取数据User user = null;ArrayList<User> users = new ArrayList<>();while (rs.next()){ //获取数据 int id = rs.getInt("id"); String username = rs.getString("username"); String password = rs.getString("password"); //创建对象设置属性值 user = new User(); user.setId(id); user.setUsername(username); user.setPassword(password); user.setGender(gender); //装入汇合 users.add(user);}可能有人会说这不是挺便捷的吗?从外表上来看如同是这么一回事,但当不难看出JDBC在其中存在不少问题 ...

January 30, 2023 · 1 min · jiezi

关于mybatis:Mybatis中ResultMap和ResultType的区别

根本映射 :(resultType)应用resultType进行输入映射,只有查问进去的列名和pojo中的属性名统一,该列才能够映射胜利。(数据库,实体,查问字段,,这些全副都得一一对应) <select id="findUserCount" parameterType="cn.edu.hpu.mybatis.PO.UserQueryVo" resultType="int"> select count(*) from user where user.sex=#{userCustom.sex} and user.username like '%${userCustom.username}%' </select> 高级映射 :(resultMap) 如果查问进去的列名和pojo的属性名不统一,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。(高级映射,字段名称能够不统一,通过映射来实现) <!-- 自定义映射规定:resultMap标签来实现映射规定的定义 id属性:标签给这个映射负责调配一个惟一的id'值,对应就是resultMap=“id属性的值” --> <resultMap id="UserEntityMap" type="com.xiaoan.store.pojo.User"> <!-- 将表的资源和类的属性不统一的字段进行匹配指定,名称统一的字段能够省略不写 --> <result column="is_delete" property="isDelete"></result> <result column="created_User" property="createdUser"></result> <result column="created_time" property="createdTime"></result> <result column="modified_user" property="modifiedUser"></result> <result column="modified_time" property="modifiedTime"></result> </resultMap><!-- User findByUsername(String username) resultType:示意查问后果集类型,只须要指定对应映射类的类型 resultMap:标签当表的资源和类的对象属性字段不统一时,来自定义查问后果集的映射规定 --> <select id="findByUsername" resultMap="UserEntityMap"> select username from t_user where username = #{username} </select>

January 19, 2023 · 1 min · jiezi

关于mybatis:MyBatis-使用resultMap-以及-一对一和一对多

记录一下从hibernate 改成 mybatis 遇到的一些问题 小问题一运行的时候忽然发现的报错: 查看过几遍之后才发现起因: 之前的时候不小心在前面减少了一个斜杠 因为编译器不会对 sql 语句进行查看, 所以运行后盾的时候并没有报错。所以过后没发现。 而过几天之后,当运行到这条sql 语句的时候, 后盾才报了错。 所以,咱们写sql 语句的时候要小心。 以防咱们写的不对, 还能够进入mysql 执行一下这条语句看看后果。 二发现问题背景: 分页的时候发现这三列数据为空 效果图: 排查问题:外部编号这一列的问题很快就排查了进去: 后盾与数据库字段名不统一 数据库: 后盾实体: 所以在咱们执行上面这条语句时,在进行实体映射的时候对应不上, 所以为null <select id="findAll" resultType="equipmentManagementSystem.entity.Equipment"> select * from equipment </select>以往的解决办法我想起了以前 前后台字段不对应时 的解决办法: @JsonProperty("internal_number")private String internalNumber;然而这个正文并没有用。 因为这个注解是json序列化时,序列化为另一个名称。 前后台就是通过 json 传递数据信息。 而目前状况是后盾与数据库的交互, ORM 把数据库映射成对象, 用不到Json。 所以此时咱们须要用到myBatis的另一个标签 resultMap。 resultMapresultMap属于mybatis返回操作后果的一个标签,能够用来映射select查问进去后果的汇合。 次要作用是将实体类中的字段与数据库表中的字段进行关联映射。 resultMap 属性: 属性形容id以后命名空间中的一个惟一标识,用于标识一个后果映射。type类的齐全限定名extends能够继承其余resultMap的一些写好的属性result属性: 属性形容id一个 ID 后果;标记出作为 ID 的后果能够帮忙进步整体性能result注入到字段或 JavaBean 属性的一般后果association一个简单类型的关联;许多后果将包装成这种类型collection一个简单类型的汇合例子: <mapper namespace="equipmentManagementSystem.Mybatis.EquipmentMapper"> <!--type指向javabean类,id可自定义 --> <resultMap id="equipmentMap" type="equipmentManagementSystem.entity.Equipment"> <id column="id" property="id"></id> <!-- property对应实体类的属性名称,column为数据库字段名 --> <result column="name" property="name"/> <result column="model" property="model"/> <result column="place" property="place"/> <result column="states" property="states"/> <result column="sale_time" property="saleTime"/> <result column="internal_number" property="internalNumber"/> </resultMap> <select id="findAll" resultMap="equipmentMap"> select * from equipment </select></mapper>这个时候, 咱们就能够在 column 属性写上 实体名,在 property 属性写上数据库名。最初就映射胜利。在列表中能够看到这列。 ...

November 30, 2022 · 1 min · jiezi

关于mybatis:把Mybatis-Generator生成的代码加上想要的注释

作者:王建乐1 前言在日常开发工作中,咱们常常用Mybatis Generator依据表构造生成对应的实体类和Mapper文件。然而Mybatis Generator默认生成的代码中,正文并不是咱们想要的,所以个别在Generator配置文件中,会设置不主动生成正文。带来的问题就是主动生成代码之后,咱们还要本人去类文件中把正文加上,如果生成的类较少还好,如果有生成很多类文件,本人加正文是一件繁琐的工作。 通过重写Mybatis Generator的CommentGenerator接口,能够不便地生成本人想要的正文,缩小反复工作。 2 应用Java形式执行Mybatis Generator2.1 IDEA中新建Maven我的项目pom.xml中引入jar包 <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>MyGenerator</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.7</version> </dependency> </dependencies></project>2.2 创立generatorConfig.xml轻易找个目录放,我放在src/main/resources目录下 <?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> <context id="mysql" defaultModelType="hierarchical" targetRuntime="MyBatis3Simple" > <!-- 生成的 Java 文件的编码 --> <property name="javaFileEncoding" value="UTF-8"/> <!-- 格式化 Java 代码 --> <property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter"/> <!-- 格式化 XML 代码 --> <property name="xmlFormatter" value="org.mybatis.generator.api.dom.DefaultXmlFormatter"/> <commentGenerator> <property name="suppressAllComments" value="false" /> </commentGenerator> <!-- 配置数据库连贯 --> <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver" connectionURL="URL" userId="user" password="password"> <!-- 设置 useInformationSchema 属性为 true --> <property name="useInformationSchema" value="true" /> </jdbcConnection> <!-- 生成实体的地位 --> <javaModelGenerator targetPackage="com.jd.bulk" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> </javaModelGenerator> <!-- 生成 Mapper XML 的地位 --> <sqlMapGenerator targetPackage="com.jd.bulk" targetProject="src/main/resources"> <property name="enableSubPackages" value="true"/> </sqlMapGenerator> <!-- 生成 Mapper 接口的地位 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.jd.bulk" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> </javaClientGenerator> <!-- 设置数据库的表名和实体类名 --> <table tableName="worker" domainObjectName="Worker"/> </context></generatorConfiguration>2.3 创立main办法,运行Generatorpublic class Generator { public static void main(String[] args) throws Exception { List<String> warnings = new ArrayList<>(2); ConfigurationParser cp = new ConfigurationParser(warnings); File configFile = new File("src/main/resources/generatorConfig.xml"); Configuration config = cp.parseConfiguration(configFile); DefaultShellCallback callback = new DefaultShellCallback(true); MyBatisGenerator = new MyBatisGenerator(config, callback, warnings); myBatisGenerator.generate(null); }}运行main办法,生成默认正文如下,并不是咱们想要的正文,所以个别会配置为正文不生成: ...

November 22, 2022 · 2 min · jiezi

关于mybatis:MyBatis快速入门

什么是框架?框架相当于是一个脚手架,外部曾经封装好了很多代码,只须要在其根底上进行开发就能够进步咱们的开发效率。 什么是MyBatis?MyBatis 是一款优良的长久层框架。它反对自定义 SQL、存储过程以及高级映射。MyBatis 罢黜了简直所有的 JDBC 代码以及设置参数和获取后果集的工作。官网文档:https://mybatis.org/mybatis-3...疾速上手我的mysql版本是5.71. 筹备数据DROP TABLE IF EXISTS user;CREATE TABLE user( id BIGINT(20) NOT NULL COMMENT '主键ID', name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名', age INT(11) NULL DEFAULT NULL COMMENT '年龄', email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱', PRIMARY KEY (id));INSERT INTO user (id, name, age, email) VALUES(1, 'Jone', 18, 'test1@baomidou.com'),(2, 'Jack', 20, 'test2@baomidou.com'),(3, 'Tom', 28, 'test3@baomidou.com'),(4, 'Sandy', 21, 'test4@baomidou.com'),(5, 'Billie', 24, 'test5@baomidou.com');2. 依赖导入<dependencies> <!-- mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.10</version> </dependency> <!-- mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.11</version> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> <scope>provided</scope> </dependency> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> </dependencies>3. JavaBean用于映射数据库: ...

September 9, 2022 · 3 min · jiezi

关于mybatis:从零开始实现一个MyBatis加解密插件

作者:vivo 互联网服务器团队- Li Gang本篇文章介绍应用MyBatis插件来实现数据库字段加解密的过程。 一、需要背景公司出于平安合规的思考,须要对明文存储在数据库中的局部字段进行加密,避免未经受权的拜访以及个人信息透露。 因为我的项目已进行迭代,革新的老本太大,因而咱们选用了MyBatis插件来实现数据库加解密,保障往数据库写入数据时能对指定字段加密,读取数据时能对指定字段解密。 二、思路解析2.1 零碎架构 对每个须要加密的字段新增密文字段(对业务有侵入),批改数据库、mapper.xml以及DO对象,通过插件的形式把针对明文/密文字段的加解密进行收口。自定义Executor对SELECT/UPDATE/INSERT/DELETE等操作的明文字段进行加密并设置到密文字段。自定义插件ResultSetHandler负责针对查问后果进行解密,负责对SELECT等操作的密文字段进行解密并设置到明文字段。2.2 零碎流程 新增加解密流程管制开关,别离管制写入时是只写原字段/双写/只写加密后的字段,以及读取时是读原字段还是加密后的字段。新增历史数据加密工作,对历史数据批量进行加密,写入到加密后字段。出于平安上的思考,流程里还会有一些校验/弥补的工作,这里不再赘述。三、计划制订3.1 MyBatis插件简介MyBatis 预留了 org.apache.ibatis.plugin.Interceptor 接口,通过实现该接口,咱们能对MyBatis的执行流程进行拦挡,接口的定义如下: public interface Interceptor { Object intercept(Invocation invocation) throws Throwable; Object plugin(Object target); void setProperties(Properties properties);}其中有三个办法: 【intercept】:插件执行的具体流程,传入的Invocation是MyBatis对被代理的办法的封装。【plugin】:应用以后的Interceptor创立代理,通常的实现都是 Plugin.wrap(target, this),wrap办法内应用 jdk 创立动静代理对象。【setProperties】:参考下方代码,在MyBatis配置文件中配置插件时能够设置参数,在setProperties函数中调用 Properties.getProperty("param1") 办法能够失去配置的值。<plugins> <plugin interceptor="com.xx.xx.xxxInterceptor"> <property name="param1" value="value1"/> </plugin></plugins>在实现intercept函数对MyBatis的执行流程进行拦挡前,咱们须要应用@Intercepts注解指定拦挡的办法。 @Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }), @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }) })参考上方代码,咱们能够指定须要拦挡的类和办法。当然咱们不能对任意的对象做拦挡,MyBatis件可拦挡的类为以下四个。 ExecutorStatementHandlerParameterHandlerResultSetHandler回到数据库加密的需要,咱们须要从下面四个类里抉择能用来实现入加入密和出参解密的类。在介绍这四个类之前,须要对MyBatis的执行流程有肯定的理解。 ...

August 23, 2022 · 4 min · jiezi

关于mybatis:Mybatis介绍使用IDEA快速入门

1. Mybatis概念MyBatis 是一款优良的长久层框架,用于简化 JDBC 开发 JavaEE三层架构:体现层、业务层、长久层JDBC 与 MyBatis 比照: MyBatis 本是 Apache 的一个开源我的项目iBatis, 2010年这个我的项目由apache software foundation 迁徙到了google code,并且改名为MyBatis 。2013年11月迁徙到Github官网:https://mybatis.org/mybatis-3... 2. Mybatis疾速入门要求:查问mybatis数据库中tb_user表的所有数据 2.1 创立模块,导入依赖创立mybatis-demo模块,在pox.xml中增加mybatis的依赖坐标 <dependencies> <!--mybatis 依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.5</version> </dependency> <!--当然除了mybatis,还有其余一些驱动--> <!--mysql 驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> <!--junit 单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> <scope>test</scope> </dependency> <!-- 增加slf4j日志api --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.20</version> </dependency> <!-- 增加logback-classic依赖 --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <!-- 增加logback-core依赖 --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency></dependencies>留神:须要在我的项目的 resources 目录下创立logback的配置文件logback.xml ...

August 16, 2022 · 1 min · jiezi

关于mybatis:mybatis的基本使用基本关联查询

所需依赖: <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.1.tmp</version>graph TD A[前台发出请求] -->|依据url匹配到c层对应办法| B(Controller) B --> C(调用服务层对应办法)那么服务层中的办法从哪里来呢(比方最简略的save、delete等)其中Iservice中次要蕴含了罕用的save、update、remove(delete)、page等办法。并且他们的实现都依赖于ServiceImpl类并且利用BaseMapper辅助实现。也就是说在mybatis中并不需要仓库层来辅助实现各项操作。 也就是说咱们如果想要实现简略的增删改查只须要配置好上述关系并在C层中进行调用即可例:对于test的增删改查 @RestController@RequestMapping("/test")public class testController { @Autowired private TestService testService; @PostMapping public RespBean addTest(@RequestBody test test){ testService.save(test); return RespBean.success("增加胜利。"); } @GetMapping() public List<test> getAllSettlement(){ return testService.list(); } @PutMapping() public RespBean updateUser(@RequestBody test test){ if(testService.updateById(test)){ RespBean.success("更新用户信息胜利"); } return RespBean.success("更新用户信息失败"); } @DeleteMapping("/{id}") public RespBean deleteTest(@PathVariable String id) { testService.removeById(id); return RespBean.success("胜利删除test"); }}说完了最根本的需要,那么要怎么依据前台传来的参数进行查问或者分页呢?这就须要配置Mapper.xml来结构查问条件并与之前定义的Mapper接口进行关联。 首先就是最根本的含糊查问: public interface TestMapper extends BaseMapper<Test> { List<Test> getTestsByName(String name);}<?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.recorde.server.mapper.TestMapper"> <!-- 通用查问映射后果 --> <!-- 即把实体中字段与数据库中字段进行对应 --> <resultMap id="BaseResultMap" type="com.recorde.server.model.Test"> <result column="id" property="id"/> <result column="name" property="name"/> </resultMap> <!-- 通用查问后果列 --> <sql id="Base_Column_List"> id , name </sql> <select id="getTestsByName" resultType="com.recorde.server.model.Test"> select * from test where name like concat('%', #{name}::text, '%') </select></mapper>其中的select项中的id就是负责和mapper中办法进行绑定从而针对此办法进行查问,标签内的内容就是sql语句间接进行查问。ManyToOne 左关联查问:数据筹备: ...

August 10, 2022 · 2 min · jiezi

关于mybatis:分享从Mybatis源码中学习到的10种设计模式

作者:小傅哥<br/>博客:https://bugstack.cn 积淀、分享、成长,让本人和别人都能有所播种!一、前言:小镇卷码家总有不少研发搭档问小傅哥:“为什么学设计模式、看框架源码、补技术常识,就一个一般的业务我的项目,会造飞机不也是天天写CRUD吗?” 你说的没错,但你天天写CRUD,你感觉 烦不? 慌不? 是不是既放心本人没有失去技术成长,也胆怯未来没法用这些都是CRUD的我的项目去加入;述职、降职、问难,甚至可能要被迫面试时,本人手里一点干货也没有的状况。 所以你/我作为一个小镇卷码家,当然要裁减本人的常识储备,否则架构,架构思维不懂、设计,设计模式不会、源码、源码学习不深,最初就用一堆CRUD写简历吗? 二、源码:学设计模式在 Mybatis 两万多行的框架源码实现中,应用了大量的设计模式来解耦工程架构中面对简单场景的设计,这些是设计模式的奇妙应用才是整个框架的精髓,这也是小傅哥喜爱卷源码的重要起因。通过小傅哥的整顿有如下10种设计模式的应用,如图所示 讲道理,如果只是把这10种设计模式背下来,等着下次面试的时候拿出来说一说,尽管能有点帮忙,不过这种学习形式就真的算是把路走窄了。就像你每说一个设计模式,能联想到这个设计模式在Mybatis的框架中,体现到哪个流程中的源码实现上了吗?这个源码实现的思路能不能用到你的业务流程开发里?别总说你的流程简略,用不上设计模式!难到因为有钱、富二代,就不考试吗? 好啦,不扯淡了,接下来小傅哥就以《手写Mybatis:渐进式源码实际》的学习,给大家列举出这10种设计模式,在Mybatis框架中都体现在哪里了! 本文对应源码仓库:https://gitcode.net/KnowledgePlanet/doc/-/wikis/home三、类型:创立型模式1. 工厂模式源码详见:cn.bugstack.mybatis.session.SqlSessionFactory public interface SqlSessionFactory { SqlSession openSession();}源码详见:cn.bugstack.mybatis.session.defaults.DefaultSqlSessionFactory public class DefaultSqlSessionFactory implements SqlSessionFactory { private final Configuration configuration; public DefaultSqlSessionFactory(Configuration configuration) { this.configuration = configuration; } @Override public SqlSession openSession() { Transaction tx = null; try { final Environment environment = configuration.getEnvironment(); TransactionFactory transactionFactory = environment.getTransactionFactory(); tx = transactionFactory.newTransaction(configuration.getEnvironment().getDataSource(), TransactionIsolationLevel.READ_COMMITTED, false); // 创立执行器 final Executor executor = configuration.newExecutor(tx); // 创立DefaultSqlSession return new DefaultSqlSession(configuration, executor); } catch (Exception e) { try { assert tx != null; tx.close(); } catch (SQLException ignore) { } throw new RuntimeException("Error opening session. Cause: " + e); } }} ...

July 18, 2022 · 6 min · jiezi

关于mybatis:Mybatis查询结果为空时为什么返回值为NULL或空集合

背景 一行数据记录如何映射成一个 Java 对象,这种映射机制是 MyBatis 作为 ORM 框架的外围性能之一,也是咱们这篇文章须要学习的内容。 开始前咱们先看一个问题:你是否已经在学习 Mybatis 的时候跟我有一样的疑难,什么状况下返回 null,什么时候是空集合,为什么会是这种后果?那么你感觉上述这种答复能压服你嘛? 我想应该不能吧,除非亲眼所见,否则真的很难确认他人说的是对还是错(毕竟网上的答案真的千奇百怪,啥都有,曾经不是第一次发现一些谬误的说法被宽泛流传了),那么这篇文章咱们就简略的剖析一下。 看完这篇你就晓得查问后果为空时候为什么汇合会是空集合而不是 NULL,而对象为什么会是 NULL 了。 PS:对过程不感兴趣的能够间接跳到最初看论断。 JDBC 中的 ResultSet 简介 你如果有 JDBC 编程教训的话,应该晓得在数据库中执行一条 Select 语句通常只能拿到一个 ResultSet,而后果集 ResultSet 是数据中查问后果返回的一种对象,能够说后果集是一个存储查问后果的对象。 然而后果集并不仅仅具备存储的性能,他同时还具备操纵数据的性能,可能实现对数据的更新等,咱们能够通过 next() 办法将指针挪动到下一行记录,而后通过 getXX() 办法来获取值。 while(rs.next()){ // 获取数据 int id = rs.getInt(1); String name = rs.getString("name"); System.out.println(id + "---" + name);}后果集解决入口 ResultSetHandler 当 MyBatis 执行完一条 select 语句,拿到 ResultSet 后果集之后,会将其交给关联的 ResultSetHandler 进行后续的映射解决。 在 MyBatis 中只提供了一个 ResultSetHandler 接口实现,即 DefaultResultSetHandler。 上面咱们就以 DefaultResultSetHandler 为核心,介绍 MyBatis 中 ResultSet 映射的外围流程。 ...

July 5, 2022 · 6 min · jiezi

关于mybatis:敲了几万行源码后我给Mybatis画了张全地图

作者:小傅哥博客:https://bugstack.cn 积淀、分享、成长,让本人和别人都能有所播种!一、说说:“产”后感触有人跟我说,手写Spring难,手写Mybatis易? 一股神奇的力量,让我在手写完 Spring 后,开始对 Mybatis 下手。最开始我也感觉 Spring 那么大都写下来了,Mybatis 能有多难?但随着我开始梳理、拆解、细化,Mybatis 框架源码的架构模型后发现,事件没那么简略! 为什么事件没那么简略?因为如果说只是为了体现出一个 ORM 框架的外围构造和性能,7/8 个类就能实现进去。但如果是实现一个残缺的串联出重要外围脉络流程的 ORM 框架,至多要在 100个类以上,能力把 Mybatis 这些性能全副串联进去。 那为什么几个类就能搞定的事要,写把开整个 Mybatis 手写一堆的代码来实现呢? 其实这里有一个十分重要的点,就是你学习源码的目标是什么,是为了面试? 为了相熟流程? 为了跟风? 其实在小傅哥看来,这些都不是学习源码的外围目标和期待的后果。咱们学习源码更多的是为了学习这些源码在面对简单零碎问题时候,如何设计工程架构,使用了什么设计准则和哪些设计模式,而这些使用到的思维在代码中又是如何落地的。 这样的货色,才是学习源码应该器重的内容,而且这也是能真的帮忙研发人员进步编码思维高度的货色。所以你会看到小傅哥逐渐拆解 Mybatis 外围功能模块,通过渐进式的逐渐开发实现,层层开展 Mybatis 的设计和实现的神秘面纱(PS:写过当前也不太神秘)。 二、源码:全貌地图在小傅哥手写完 Mybatis 框架当前,梳理了一张全貌地图,预览整个 Mybatis 框架的执行脉络体系。有了这张关上了和平迷雾地图的指引,再学习起来 Mybatis 的技术,也就变得十分清晰了。 这是整个《手写 Mybatis》的全貌地图,小傅哥会带着大家逐渐实现这外面的功能模块,分章节细化各个模块的实现流程,最终让读者实现出一个丰盛、全面、粗疏的 ORM 框架。在学习的过程中,大家也能够参考这张图来对照手写的代码以及 Mybatis 的源码,这样更加有利于对 Mybatis 框架的了解。通常如果你不是四分五裂的拼凑式学习,而是成体系的建设本人的常识栈,那么你在学习后,也肯定能梳理出一套对于学习过内容的技术地图。三、查看:小册目录要吹牛了! 傅哥,手写Mybatis 而已,你怎么把 Mybatis 都手写了! 哈哈哈,写的爽了,就顺便都给敲了,包含:解析、绑定、反射、缓存、事务,这还有注解、数据源、MetaObject 都给干了! 1. 目录 博客:https://bugstack.cn - 博客菜单中 Spring 栏目下 -> 手撸 Mybatis阐明:在18章课程中,会逐渐带着读者手写出一套 Mybatis 框架,并且是一套串联所有外围流程的 Mybatis 框架,浏览学习后会对 ORM 源码有透彻清晰的理解。2. 源码 ...

June 20, 2022 · 1 min · jiezi

关于mybatis:mybatis源码分析

mybatis 个别集成到spring框架中应用,上面介绍如何在spring中应用mybatis 创立datasource实例 <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> </property> <property name="url"> <value>jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8</value> </property> <property name="username"> <value>root</value> </property> <property name="password"> <value>xxx</value> </property> </bean>创立SqlSessionFactoryBean 实例 <bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="plugins"> <array> <bean class="com.learn.springmybatis.ExecutorInterceptor"></bean> </array> </property> </bean>创立数据库操作的bean <bean id="userDao" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" value="com.learn.springmybatis.UserDao"/> <property name="sqlSessionFactory" ref="sqlSession"></property> </bean>当然还有具体java代码,这里不体现进去。列出上述配置次要阐明mybatis应用的大体流程。业务代码最终是拿数据库操作bean实例,如userDao去操作数据库。那咱们就从userDao开始吧,看看业务代码通过mybatis是如何和db打交道的。 userDao的实例化过程上面是UserDao的java代码,一个Interface,外面除了有一个注解,啥都没有。那么它是如何实现数据插入的呢? public interface UserDao { @Insert(" insert into user ( id, name, title ) values (#{id},#{name}, #{title}) ") public int insert(User user);}userDao是MapperFactoryBean创立的 从xml配置咱们能够得悉,userDao是MapperFactoryBean创立,而MapperFactoryBean实现类FactoryBean接口,Spring的FactoryBean能够依据须要创立不同类型的bean 通过MapperFactoryBean的getObject获取userDao实例 public T getObject() throws Exception { return this.getSqlSession().getMapper(this.mapperInterface); }this.getSqlSession()是new SqlSessionTemplate(sqlSessionFactory) 最终进入Configuration的getMapper ...

June 14, 2022 · 1 min · jiezi

关于mybatis:Mybatis-手撸专栏第10章使用策略模式调用参数处理器

作者:小傅哥博客:https://bugstack.cn 积淀、分享、成长,让本人和别人都能有所播种!一、前言你这代码写的,咋这么轴呢! 说到轴,让我想起初中上学时老师说的话:“你那脑瓜子,咋跟手焖子似的!” 西南话手焖子就是那种冬天戴的大棉手套,棉手套里的棉花都被压的又沉又硬的了,所以来比喻脑瓜子笨。 而写轴代码的大部分都是刚毕业没多久,或者刚开始工作的码农,毕竟经验不足经验不多,写出一些不太好保护的代码也情有可原。而那些绝对多数锤炼进去的老码农,其实代码的稳固水平、设计教训、周密逻辑,都是相对来说要好很多的。当然一部分老码农,只是老了而已,代码还是那个代码! 所以企业招聘些年轻人,须要年老的思维。但没必要嚯嚯只是头发没多少的老码农,否则谁来给你安稳落地你那些天马行空的想法呢!难道体验、稳固、晦涩,不应该是更值得谋求的,非得喜爱全是愣头青似的代码,写出几百个bug,造成大量资损和客诉,让老板感觉很爽? 二、指标上一章节,小傅哥带着大家细化的 XML 语句构建器,解耦在解析 XML 中的所须要解决的 Mapper 信息,包含;SQL、入参、出参、类型,并对这些信息进行记录到 ParameterMapping 参数映射解决类中。那么这个一章节咱们将联合这部分参数的提取,对执行的 SQL 进行参数的自动化设置,而不是像咱们之前那样把参数写成固定的,如图 10-1 所示 在流程上,通过 DefaultSqlSession#selectOne 办法调用执行器,并通过预处理语句处理器 PreparedStatementHandler 执行参数设置和后果查问。那么这个流程中咱们所解决的参数信息,也就是每个 SQL 执行时,那些?号 须要被替换的中央,目前是通过硬编码的形式进行解决的。而这就是本章节须要解决的问题,如果只是硬编码实现参数设置,那么对于所有那些不同类型的参数就没法进行操作了。所以本章节须要联合联合上一章节所实现的语句构建器对 SQL 参数信息的拆解,本章将会依照这些参数的解析,解决这里硬编码为自动化类型设置。针对不同类型的参数设置,这部分应用了什么设计模式呢?三、设计这里能够思考下,参数的解决也就是通常咱们应用 JDBC 间接操作数据库时,所应用 ps.setXxx(i, parameter); 设置的各类参数。那么在自动化解析 XML 中 SQL 拆分出所有的参数类型后,则应该依据不同的参数进行不同的类型设置,也就;Long 调用 ps.setLong、String 调用 ps.setString 所以这里须要应用策略模式,在解析 SQL 时依照不同的执行策略,封装进去类型处理器(也就是是实现 TypeHandler<T> 接口的过程)。整体设计如图 10-2 所示 其实对于参数的解决,因为有很多的类型(Long\String\Object\...),所以这里最重要的体现则是策略模式的应用。这里包含了构建参数时依据类型,抉择对应的策略类型处理器,填充到参数映射汇合中。另外一方面是参数的应用,也就是在执行 DefaultSqlSession#selectOne 的链路中,包含了参数的设置,依照参数的不同类型,获取出对应的处理器,以及入参值。留神:因为入参值可能是一个对象中的属性,所以这里咱们用到了后面章节实现的反射类工具 MetaObject 进行值的获取,防止因为动静的对象,没法硬编码获取属性值。四、实现1. 工程构造mybatis-step-09└── src ├── main │ └── java │ └── cn.bugstack.mybatis │ ├── binding │ │ ├── MapperMethod.java │ │ ├── MapperProxy.java │ │ ├── MapperProxyFactory.java │ │ └── MapperRegistry.java │ ├── builder │ │ ├── xml │ │ │ ├── XMLConfigBuilder.java │ │ │ ├── XMLMapperBuilder.java │ │ │ └── XMLStatementBuilder.java │ │ ├── BaseBuilder.java │ │ ├── ParameterExpression.java │ │ ├── SqlSourceBuilder.java │ │ └── StaticSqlSource.java │ ├── datasource │ ├── executor │ │ ├── resultset │ │ │ └── ParameterHandler.java │ │ ├── resultset │ │ │ ├── DefaultResultSetHandler.java │ │ │ └── ResultSetHandler.java │ │ ├── statement │ │ │ ├── BaseStatementHandler.java │ │ │ ├── PreparedStatementHandler.java │ │ │ ├── SimpleStatementHandler.java │ │ │ └── StatementHandler.java │ │ ├── BaseExecutor.java │ │ ├── Executor.java │ │ └── SimpleExecutor.java │ ├── io │ ├── mapping │ │ ├── BoundSql.java │ │ ├── Environment.java │ │ ├── MappedStatement.java │ │ ├── ParameterMapping.java │ │ ├── SqlCommandType.java │ │ └── SqlSource.java │ ├── parsing │ ├── reflection │ ├── scripting │ │ ├── defaults │ │ │ └── DefaultParameterHandler.java │ │ ├── xmltags │ │ │ ├── DynamicContext.java │ │ │ ├── MixedSqlNode.java │ │ │ ├── SqlNode.java │ │ │ ├── StaticTextSqlNode.java │ │ │ ├── XMLLanguageDriver.java │ │ │ └── XMLScriptBuilder.java │ │ ├── LanguageDriver.java │ │ └── LanguageDriverRegistry.java │ ├── session │ │ ├── defaults │ │ │ ├── DefaultSqlSession.java │ │ │ └── DefaultSqlSessionFactory.java │ │ ├── Configuration.java │ │ ├── ResultHandler.java │ │ ├── SqlSession.java │ │ ├── SqlSessionFactory.java │ │ ├── SqlSessionFactoryBuilder.java │ │ └── TransactionIsolationLevel.java │ ├── transaction │ └── type │ ├── BaseTypeHandler.java │ ├── JdbcType.java │ ├── LongTypeHandler.java │ ├── StringTypeHandler.java │ ├── TypeAliasRegistry.java │ ├── TypeHandler.java │ └── TypeHandlerRegistry.java └── test ├── java │ └── cn.bugstack.mybatis.test.dao │ ├── dao │ │ └── IUserDao.java │ ├── po │ │ └── User.java │ └── ApiTest.java └── resources ├── mapper │ └──User_Mapper.xml └── mybatis-config-datasource.xml工程源码:https://github.com/fuzhengwei/small-mybatis ...

May 30, 2022 · 6 min · jiezi

关于mybatis:Mybatis业务逻辑2

持续在Mybatis业务逻辑(1)的代码根底上扩大。———————————————————————————————————————— 数据库增加用户,查问所有用户Dao package com.example.demo.dao;@Repositorypublic interface UserDao { public User getUserById(@Param("Userid") int id); public List<User> getUserByAge(@Param("age") int age); public void addUser(User user); public List<User> getAllUser();}对应的Mapper.xml <insert id="addUser" parameterType="User" useGeneratedKeys="true" keyProperty="id"> INSERT INTO user(id,username,password,age) Values (#{id},#{username},#{password},#{age}) </insert> <select id="getAllUser" resultType="com.example.demo.entity.User"> select * from `user` </select>其中 useGeneratedKeys=“true” keyProperty=“id”useGeneratedKeys设置为 true 时,示意如果插入的表id以自增列为主键,则容许 JDBC 反对主动生成主键,并可将主动生成的主键id返回。useGeneratedKeys参数只针对 insert 语句失效,默认为 false; 测试增加数据库信息在pom.xml引入以下依赖,以应用类RandomStringUtils生成随机数 <dependencies> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <scope>test</scope> </dependency> </dependencies> @Test//数据库随机增加用户 public void test3(){ for(int i=150;i<1000;i++){ String username= RandomStringUtils.randomAlphanumeric(5); String password= RandomStringUtils.randomAlphanumeric(5);//符号长度 userService.addUser(new User(i,username,password,i-1)); } } @Test //验证test3并查看所有用户 public void test4(){ List<User> UserAll = userService.findAll(); System.out.println(UserAll.toString()); }}操作台输入 ...

May 17, 2022 · 1 min · jiezi

关于mybatis:Mybatis-手撸专栏第8章把反射用到出神入化

作者:小傅哥博客:https://bugstack.cn - 系列内容 积淀、分享、成长,让本人和别人都能有所播种!一、前言为什么,读不懂框架源码? 咱们都晓得作为一个程序员,如果想学习到更深层次的技术,就须要浏览大量的框架源码,学习这些框架源码中的开发套路和设计思维,从而晋升本人的编程能力。 事大家都分明,但在实操上,很多码农基本没法浏览框架源码。首先一个十分大的问题是,面对如此宏大的框架源码,不晓得从哪下手。与平时的业务需要开发相比,框架源码中使用了大量的设计准则和设计模式对系统性能进行解耦和实现,也应用了不少如反射、代理、字节码等相干技术。 当你还认为是平时的业务需要中的实例化对象调用办法,去找寻源码中的流程时,可能基本就找不到它是何时发动调用的、怎么进行传参、在哪解决赋值的等一连串的问题,都把一个好码农劝退在开始学习的路上。 二、指标不晓得大家在学习《手写 Mybatis》的过程中,是否有对照 Mybatis 源码一起学习,如果你有对照源码,那么大概率会发现咱们在实现数据源池化时,对于属性信息的获取,采纳的是硬编码的形式。如图 8-1 所示 也就是 props.getProperty("driver")、props.getProperty("url") 等属性,都是通过手动编码的形式获取的。那其实像 driver、url、username、password 不都是规范的固定字段吗,这样获取有什么不对的。如果依照咱们当初的了解来说,并没有什么不对,但其实除了这些字段以外,可能还有时候会配置一些扩大字段,那么怎么获取呢,总不能每次都是硬编码。所以如果你有浏览 Mybatis 的源码,会发现这里应用了 Mybatis 本人实现的元对象反射工具类,能够实现一个对象的属性的反射填充。这块的工具类叫做 MetaObject 并提供相应的;元对象、对象包装器、对象工厂、对象包装工厂以及 Reflector 反射器的应用。那么本章节咱们就来实现一下反射工具包的内容,因为随着咱们后续的开发,也会有很多中央都须要应用反射器优雅的解决咱们的属性信息。这也能为你增加一些对于反射的弱小的应用!三、设计如果说咱们须要对一个对象的所提供的属性进行对立的设置和获取值的操作,那么就须要把以后这个被解决的对象进行解耦,提取出它所有的属性和办法,并依照不同的类型进行反射解决,从而包装成一个工具包。如图 8-2 所示 其实整个设计过程都以围绕如何拆解对象并提供反射操作为主,那么对于一个对象来说,它所包含的有对象的构造函数、对象的属性、对象的办法。而对象的办法因为都是获取和设置值的操作,所以根本都是get、set解决,所以须要把这些办法在对象拆解的过程中须要摘取进去进行保留。当真正的开始操作时,则会依赖于曾经实例化的对象,对其进行属性解决。而这些处理过程理论都是在应用 JDK 所提供的反射进行操作的,而反射过程中的办法名称、入参类型都曾经被咱们拆解和解决了,最终应用的时候间接调用即可。四、实现1. 工程构造mybatis-step-07└── src ├── main │ └── java │ └── cn.bugstack.mybatis │ ├── binding │ ├── builder │ ├── datasource │ │ ├── druid │ │ │ └── DruidDataSourceFactory.java │ │ ├── pooled │ │ │ ├── PooledConnection.java │ │ │ ├── PooledDataSource.java │ │ │ ├── PooledDataSourceFactory.java │ │ │ └── PoolState.java │ │ ├── unpooled │ │ │ ├── UnpooledDataSource.java │ │ │ └── UnpooledDataSourceFactory.java │ │ └── DataSourceFactory.java │ ├── executor │ ├── io │ ├── mapping │ ├── reflection │ │ ├── factory │ │ │ ├── DefaultObjectFactory.java │ │ │ └── ObjectFactory.java │ │ ├── invoker │ │ │ ├── GetFieldInvoker.java │ │ │ ├── Invoker.java │ │ │ ├── MethodInvoker.java │ │ │ └── SetFieldInvoker.java │ │ ├── property │ │ │ ├── PropertyNamer.java │ │ │ └── PropertyTokenizer.java │ │ ├── wrapper │ │ │ ├── BaseWrapper.java │ │ │ ├── BeanWrapper.java │ │ │ ├── CollectionWrapper.java │ │ │ ├── DefaultObjectWrapperFactory.java │ │ │ ├── MapWrapper.java │ │ │ ├── ObjectWrapper.java │ │ │ └── ObjectWrapperFactory.java │ │ ├── MetaClass.java │ │ ├── MetaObject.java │ │ ├── Reflector.java │ │ └── SystemMetaObject.java │ ├── session │ ├── transaction │ └── type └── test ├── java │ └── cn.bugstack.mybatis.test.dao │ ├── dao │ │ └── IUserDao.java │ ├── po │ │ └── User.java │ ├── ApiTest.java │ └── ReflectionTest.java └── resources ├── mapper │ └──User_Mapper.xml └── mybatis-config-datasource.xml工程源码:https://github.com/fuzhengwei/small-mybatis ...

May 16, 2022 · 7 min · jiezi

关于mybatis:Mybatis-Generator

pom.xml <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-typehandlers-jsr310</artifactId> </dependency>generatorConfig.xml<?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> <properties resource="generatorConfig.properties"/> <context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat"> <property name="beginningDelimiter" value="`"/> <property name="endingDelimiter" value="`"/> <property name="runtimeCatalog" value="true"/> <plugin type="${mapper.plugin}"> <property name="mappers" value="${mapper.Mapper}"/> </plugin> <plugin type="org.mybatis.generator.plugins.SerializablePlugin"/> <jdbcConnection driverClass="${jdbc.driverClass}" connectionURL="${jdbc.url}" userId="${jdbc.user}" password="${jdbc.password}"> </jdbcConnection> <javaTypeResolver> <property name="forceBigDecimals" value="false"/> <property name="useJSR310Types" value="true"/> </javaTypeResolver> <javaModelGenerator targetPackage="${targetModelPackage}" targetProject="${targetJavaProject}"/> <sqlMapGenerator targetPackage="${targetMapperPackage}" targetProject="${targetResourcesProject}"/> <javaClientGenerator targetPackage="${targetMapperPackage}" targetProject="${targetJavaProject}" type="XMLMAPPER"/> <!-- 表配置 tableName 表名 domainObjectName java类名,首字母必须大写,否则报字符串越界谬误 --> <!-- Base --> <!-- <table tableName="base_app" domainObjectName="base.AppDao">--> <!-- <generatedKey column="id" sqlStatement="Mysql" identity="true"/>--> <!-- <columnOverride column="status" javaType="com.hehewang.hhw.app.common.enums.dao.SimpleStatusEnum"/>--> <!-- <columnOverride column="platform" javaType="com.hehewang.hhw.app.common.enums.dao.AppPlatformEnum"/>--> <!-- </table>--> </context></generatorConfiguration>generatorConfig.properties# 数据库配置jdbc.driverClass = com.mysql.cj.jdbc.Driverjdbc.url = jdbc:mysql://192.168.1.201:13306/hhw_dev?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTCjdbc.user = hhw_devjdbc.password = mysql:hhw_dev:4f0LFwIPSp8Iyogk#c3p0jdbc.maxPoolSize = 50jdbc.minPoolSize = 10jdbc.maxStatements = 100jdbc.testConnection = true# 通用Mapper配置mapper.plugin = tk.mybatis.mapper.generator.MapperPluginmapper.Mapper = com.hehewang.hhw.app.common.util.ApiMapper# domaintargetModelPackage = com.hehewang.hhw.app.common.dao# mappertargetMapperPackage = com.hehewang.hhw.app.common.mappertargetJavaProject = app-common/src/main/javatargetResourcesProject = app-common/src/main/resourcesMybatisGeneratorRun.javapackage xxx.app.common.generator;import org.mybatis.generator.api.ShellRunner;import java.io.IOException;public class MybatisGeneratorRun{ public static void main(String[] args) throws IOException, InterruptedException { // 生成dao文件 args = new String[] { "-configfile", "app-common/src/test/resources/generatorConfig.xml", "-overwrite" }; ShellRunner.main(args); // 备份 TODO Mysql服务器降级// MySqlDumpTest dump = new MySqlDumpTest();// dump.before();// dump.bumpSchema();// 构造// dump.bumpData();// 数据 }}

May 7, 2022 · 1 min · jiezi

关于mybatis:Mybatis-手撸专栏第7章SQL执行器的定义和实现

作者:小傅哥博客:https://bugstack.cn - 《手写Mybatis系列》 一、前言为什么,要读框架源码? 因为手里的业务工程代码太拉胯了!通常作为业务研发,所开发进去的代码,大部分都是一连串的流程化解决,短少性能逻辑的解耦,有着迭代频繁但可迭代性差的特点。所以这样的代码通常只能学习业务逻辑,却很难排汇到大型零碎设计和性能逻辑实现的成功经验,往往都是失败的教训。 而所有零碎的设计和实现,外围都在于如何解耦,如果解耦不清晰最初间接导致的就是再持续迭代性能时,会让整个零碎的实现越来越臃肿,稳定性越来越差。而对于解耦的实际在各类框架的源码中都有十分不错的设计实现,所以浏览这部分源码,就是在排汇胜利的教训。把解耦的思维逐渐使用到理论的业务开发中,才会让咱们写出更加优良的代码构造。 二、指标在上一章节咱们实现了有/无连接池的数据源,能够在调用执行SQL的时候,通过咱们实现池化技术实现数据库的操作。 那么对于池化数据源的调用、执行和后果封装,目前咱们还都只是在 DefaultSqlSession 中进行发动 如图 7-1 所示。那么这样的把代码流程写死的形式必定不适合于咱们扩大应用,也不利于 SqlSession 中每一个新增定义的办法对池化数据源的调用。 解耦 DefaultSqlSession#selectOne 办法中对于对数据源的调用、执行和后果封装,提供新的功能模块代替这部分硬编码的逻辑解决。只有提供了独自的执行办法入口,咱们能力更好的扩大和应答这部分内容里的需要变动,包含了各类入参、后果封装、执行器类型、批处理等,来满足不同款式的用户需要,也就是配置到 Mapper.xml 中的具体信息。三、设计从咱们对 ORM 框架渐进式的开发过程上,能够分出的执行动作包含,解析配置、代理对象、映射办法等,直至咱们后面章节对数据源的包装和应用,只不过咱们把数据源的操作硬捆绑到了 DefaultSqlSession 的执行办法上了。 那么当初为理解耦这块的解决,则须要独自提出一块执行器的服务性能,之后将执行器的性能随着 DefaultSqlSession 创立时传入执行器性能,之后具体的办法调用就能够调用执行器来解决了,从而解耦这部分功能模块。如图 7-2 所示。 首先咱们要提取出执行器的接口,定义出执行办法、事务获取和相应提交、回滚、敞开的定义,同时因为执行器是一种规范的执行过程,所以能够由抽象类进行实现,对过程内容进行模板模式的过程包装。在包装过程中定义抽象类,由具体的子类来实现。这一部分在下文的代码中会体现到 SimpleExecutor 简略执行器实现中。之后是对 SQL 的解决,咱们都晓得在应用 JDBC 执行 SQL 的时候,分为了简略解决和预处理,预处理中包含筹备语句、参数化传递、执行查问,以及最初的后果封装和返回。所以咱们这里也须要把 JDBC 这部分的步骤,分为结构化的类过程来实现,便于性能的拓展。具体代码次要体现在语句处理器 StatementHandler 的接口实现中。四、实现1. 工程构造mybatis-step-06└── src ├── main │ └── java │ └── cn.bugstack.mybatis │ ├── binding │ │ ├── MapperMethod.java │ │ ├── MapperProxy.java │ │ ├── MapperProxyFactory.java │ │ └── MapperRegistry.java │ ├── builder │ ├── datasource │ ├── executor │ │ ├── resultset │ │ │ ├── DefaultResultSetHandler.java │ │ │ └── ResultSetHandler.java │ │ ├── statement │ │ │ ├── BaseStatementHandler.java │ │ │ ├── PreparedStatementHandler.java │ │ │ ├── SimpleStatementHandler.java │ │ │ └── StatementHandler.java │ │ ├── BaseExecutor.java │ │ ├── Executor.java │ │ └── SimpleExecutor.java │ ├── io │ ├── mapping │ ├── session │ │ ├── defaults │ │ │ ├── DefaultSqlSession.java │ │ │ └── DefaultSqlSessionFactory.java │ │ ├── Configuration.java │ │ ├── ResultHandler.java │ │ ├── SqlSession.java │ │ ├── SqlSessionFactory.java │ │ ├── SqlSessionFactoryBuilder.java │ │ └── TransactionIsolationLevel.java │ ├── transaction │ └── type └── test ├── java │ └── cn.bugstack.mybatis.test.dao │ ├── dao │ │ └── IUserDao.java │ ├── po │ │ └── User.java │ └── ApiTest.java └── resources ├── mapper │ └──User_Mapper.xml └── mybatis-config-datasource.xml工程源码:公众号「bugstack虫洞栈」,回复:手写Mybatis,获取残缺源码 ...

May 5, 2022 · 5 min · jiezi

关于mybatis:MybatisPlus不支持联合主键复合主键怎么办试试MybatisTiny

Mybatis-Tiny是什么Mybatis-Tiny是一个基于Mybatis框架的一层极简的扩大,它旨在应用DSL的形式对单表进行CRUD操作,相似于Mybatis-Plus框架,但它绝不是反复造轮子!区别于别的相似框架(如Mybatis-Plus、Fluent-Mybatis等)的实现形式,它采纳一种逆向曲线救国的实现形式,通过较少的代码,极简的扩大实现了相似于他们大多数的性能,齐全满足日常开发中对单表的各种CRUD操作。 我的项目地址:https://github.com/penggle/my... 联结主键应用案例引入并应用Mybatis-Tiny(以下基于SpringBoot形式应用Mybatis) 引入依赖<dependency> <groupId>io.github.penggle</groupId> <artifactId>mybatis-tiny-core</artifactId> <!-- 版本阐明:3.5指的是基于Mybatis 3.5.x版本的意思 --> <version>3.5</version></dependency>相干配置引入相干Maven依赖后在SpringBoot启动类上应用注解@EnableMybatisTiny即可,例如: import com.penglecode.codeforce.mybatistiny.EnableMybatisTiny;import com.penglecode.codeforce.mybatistiny.examples.BasePackage;import org.springframework.boot.autoconfigure.SpringBootApplication;@EnableMybatisTiny@SpringBootApplication(scanBasePackageClasses=BasePackage.class)public class MybatisTinyExampleApplication { public static void main(String[] args) { SpringApplication.run(MybatisTinyExampleApplication.class, args); }}mybatis-spring-boot-starter及DataSource的配置依旧就好了,application.yml例如: #SpringBoot利用的名称spring: application: name: mybatis-tiny-examples-springboot #Hikari 连接池配置 datasource: hikari: #连接池名字 pool-name: defaultHikariCP #最小闲暇连贯数量 minimum-idle: 5 #闲暇连贯存活最大工夫,默认600000(10分钟) idle-timeout: 180000 #连接池最大连接数,默认是10 maximum-pool-size: 10 #池中连贯的默认主动提交行为,默认值true auto-commit: true #池中连贯的最长生命周期,0示意有限生命周期,默认1800000(30分钟) max-lifetime: 1800000 #期待来自池的连贯的最大毫秒数,默认30000(30秒) connection-timeout: 30000 #连贯测试语句 connection-test-query: SELECT 1 username: root password: 123456 url: jdbc:mysql://127.0.0.1:3306/examples?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false&rewriteBatchedStatements=true&useCursorFetch=true#Mybatis-SpringBoot配置mybatis: config-location: classpath:config/mybatis/mybatis-config.xml mapper-locations: classpath*:com/penglecode/codeforce/mybatistiny/examples/**/*Mapper.xml type-aliases-package: com.penglecode.codeforce.mybatistiny.examples type-aliases-super-type: com.penglecode.codeforce.common.domain.DomainObject基于Mybatis-Tiny的联结主键应用案例基于注解的实体对象定义:package com.penglecode.samples.order.domain.model;import com.penglecode.codeforce.common.domain.EntityObject;import com.penglecode.codeforce.mybatistiny.annotations.GenerationType;import com.penglecode.codeforce.mybatistiny.annotations.Id;import com.penglecode.codeforce.mybatistiny.annotations.Table;import com.penglecode.samples.order.domain.enums.OrderStatusEnum;/** * 主订单信息 */@Table("t_order")public class Order implements EntityObject { /** 订单ID */ @Id(strategy=GenerationType.NONE) private Long orderId; /** 客户ID */ private Long customerId; /** 总金额(单位分) */ private Long totalAmount; /** 总运费(单位分) */ private Long totalFreight; /** 商户ID */ private Long shopId; /** 下单工夫 */ private String orderTime; /** 订单状态 */ private OrderStatusEnum orderStatus; /** 订单备注 */ private String remark; private String createTime; private String updateTime; //getter/setter省略 @Override public Long identity() { return orderId; }}package com.penglecode.samples.order.domain.model;import com.penglecode.codeforce.common.domain.EntityObject;import com.penglecode.codeforce.common.domain.ID;import com.penglecode.codeforce.mybatistiny.annotations.GenerationType;import com.penglecode.codeforce.mybatistiny.annotations.Id;import com.penglecode.codeforce.mybatistiny.annotations.Table;import com.penglecode.samples.order.domain.enums.OrderStatusEnum;/** * 订单明细 */@Table("t_order_line")public class OrderLine implements EntityObject { /** 订单ID */ @Id(strategy= GenerationType.NONE) private Long orderId; /** 商品ID */ @Id(strategy=GenerationType.NONE) private Long productId; /** 商品名称 */ private String productName; /** 商品详情页URL */ private String productUrl; /** 商品单价(单位分) */ private Long unitPrice; /** 购买数量 */ private Integer quantity; /** 运费 */ private Long freight; /** 小计(单位分) */ private Long subTotalAmount; /** 订单状态 */ private OrderStatusEnum orderStatus; /** 下单工夫 */ private String orderTime; private String createTime; private String updateTime; //getter/setter省略 @Override public ID identity() { //联结主键 return new ID().addKey("orderId", orderId).addKey("productId", productId); }}/** * 订单状态 */public enum OrderStatusEnum { WAIT_PAY, PAIED, REFUND, CLOSED}实体Mapper接口定义:@Mapperpublic interface OrderMapper extends BaseEntityMapper<Order> {}@Mapperpublic interface OrderLineMapper extends BaseEntityMapper<OrderLine> {}CRUD应用示例:@SpringBootTest(classes=SamplesApplication.class)public class OrderMapperTest { @Autowired private OrderMapper orderMapper; @Autowired private OrderLineMapper orderLineMapper; @Autowired private DataSourceTransactionManager dataSourceTransactionManager; protected <T> void doInTransaction(Supplier<T> executor) { new TransactionTemplate(dataSourceTransactionManager).execute(status -> executor.get()); } @Test public void createOrder() { doInTransaction(this::doCreateOrder); } protected Object doCreateOrder() { String nowTime = DateTimeUtils.formatNow(); //Long orderId = System.currentTimeMillis(); Long orderId = 1651560129068L; List<OrderLine> orderLines = new ArrayList<>(); OrderLine orderLine1 = new OrderLine(); orderLine1.setProductId(100026667880L); orderLine1.setProductName("Apple iPhone 13 (A2634) 128GB 午夜色 反对挪动联通电信5G 双卡双待手机"); orderLine1.setProductUrl("https://item.jd.com/100026667880.html"); orderLine1.setUnitPrice(599900L); orderLine1.setQuantity(1); orderLine1.setFreight(0L); orderLines.add(orderLine1); OrderLine orderLine2 = new OrderLine(); orderLine2.setProductId(100034710000L); orderLine2.setProductName("Apple iPad Air5 10.9英寸平板电脑 2022年款(64G WLAN版/M1芯片Liquid视网膜屏 MME23CH/A) 紫色"); orderLine2.setProductUrl("https://item.jd.com/100034710000.html"); orderLine2.setUnitPrice(439900L); orderLine2.setQuantity(1); orderLine2.setFreight(0L); orderLines.add(orderLine2); Order order = new Order(); order.setOrderId(orderId); order.setOrderTime(nowTime); order.setCustomerId(123L); order.setShopId(1000000127L); order.setTotalAmount(0L); order.setTotalFreight(0L); order.setOrderStatus(OrderStatusEnum.WAIT_PAY); order.setCreateTime(nowTime); order.setUpdateTime(nowTime); for(OrderLine orderLine : orderLines) { orderLine.setOrderId(orderId); orderLine.setSubTotalAmount(orderLine.getUnitPrice() * orderLine.getQuantity()); order.setTotalFreight(order.getTotalFreight() + orderLine.getFreight()); order.setTotalAmount(order.getTotalAmount() + orderLine.getSubTotalAmount()); orderLine.setOrderStatus(order.getOrderStatus()); orderLine.setOrderTime(nowTime); orderLine.setCreateTime(nowTime); orderLine.setUpdateTime(nowTime); } //insert主订单信息 orderMapper.insert(order); //批量insert订单明细 orderLineMapper.batchUpdate(orderLines, orderLine -> orderLineMapper.insert(orderLine)); return orderId; } @Test public void updateOrder() { doInTransaction(this::doUpdateOrder); } protected Object doUpdateOrder() { Long orderId = 1651560129068L; String nowTime = DateTimeUtils.formatNow(); OrderStatusEnum targetOrderStatus = OrderStatusEnum.PAIED; Map<String,Object> orderUpdateColumns = MapLambdaBuilder.<Order>ofEmpty() .withOverride(Order::getOrderStatus, targetOrderStatus) .withOverride(Order::getRemark, "已付款,请发顺丰快递!") .withOverride(Order::getUpdateTime, nowTime) .build(); orderMapper.updateById(orderId, orderUpdateColumns); //更新主订单 Map<String,Object> orderLineUpdateColums = MapLambdaBuilder.<OrderLine>ofEmpty() .withOverride(OrderLine::getOrderStatus, targetOrderStatus) .withOverride(OrderLine::getUpdateTime, nowTime) .build(); QueryCriteria<OrderLine> orderLineUpdateCriteria = LambdaQueryCriteria.ofSupplier(OrderLine::new) .eq(OrderLine::getOrderId, orderId); orderLineMapper.updateByCriteria(orderLineUpdateCriteria, orderLineUpdateColums); //更新子订单 return orderId; } @Test public void getOrderById() { Long orderId = 1651560129068L; Order order = orderMapper.selectById(orderId); //依据单个ID查问 System.out.println(JsonUtils.object2Json(order)); //联结主键 List<ID> orderLineIds = new ArrayList<>(); orderLineIds.add(new ID().addKey(OrderLine::getOrderId, orderId).addKey(OrderLine::getProductId, 100026667880L)); orderLineIds.add(new ID().addKey(OrderLine::getOrderId, orderId).addKey(OrderLine::getProductId, 100034710000L)); List<OrderLine> orderLines = orderLineMapper.selectListByIds(orderLineIds); //依据多个ID查问 orderLines.forEach(orderLine -> System.out.println(JsonUtils.object2Json(orderLine))); }}打印SQL: ...

May 3, 2022 · 4 min · jiezi

关于mybatis:MybatisTiny一个比MybatisPlus用着更顺手的框架

根本简介Mybatis-Tiny是什么?Mybatis-Tiny是一个基于Mybatis框架的一层极简的扩大,它旨在应用DSL的形式对单表进行CRUD操作,相似于Mybatis-Plus框架,但它绝不是反复造轮子!区别于别的相似框架(如Mybatis-Plus、Fluent-Mybatis等)的实现形式,它采纳一种逆向曲线救国的实现形式,通过较少的代码,极简的扩大实现了相似于他们大多数的性能,齐全满足日常开发中对单表的各种CRUD操作。 我的项目地址:https://github.com/penggle/my... 疾速入门Talk is cheap,show me the code!插入操作ProductBaseInfo productBase = ...;List<ProductSaleSpec> productSaleSpecs = ...;productBaseInfoMapper.insert(productBase);//基于JDBC-Batch个性的批量插入操作。productSaleSpecMapper.batchUpdate(productSaleSpecs, productSaleSpec -> productSaleSpecMapper.insert(productSaleSpec));//打印日志: - ==> Preparing: INSERT INTO t_product_base_info( product_id, product_name, product_url, product_tags, product_type, audit_status, online_status, shop_id, remark, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) - ==> Parameters: null, 24期免息【当天发】Huawei/华为Mate40 5G手机官网旗舰店50pro直降mate40e官网30副品4G鸿蒙副品30全网通(String), https://detail.tmall.com/item.htm?id=633658852628(String), ["手机通信","手机","手机"](String), 1(Integer), 0(Integer), 1(Integer), 111212422(Long), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - <== Updates: 1 - ==> Preparing: INSERT INTO t_product_sale_spec( product_id, spec_no, spec_name, spec_index, remark, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? ) - ==> Parameters: 1(Long), 101(String), 4G全网通(String), 1(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 102(String), 5G全网通(String), 2(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 201(String), 亮彩色(String), 1(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 202(String), 釉红色(String), 2(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 203(String), 秘银色(String), 3(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 204(String), 夏日胡杨(String), 4(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 205(String), 秋日胡杨(String), 5(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 301(String), 8+128GB(String), 1(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 302(String), 8+256GB(String), 2(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String)更新操作//依据ID更新ProductBaseInfo productBase = ...;Map<String,Object> updateColumns1 = MapLambdaBuilder.of(productBase) //取productBase实例中对应字段的值 .with(ProductBaseInfo::getProductName) .with(ProductBaseInfo::getRemark) //如果productBase实例中对应字段的值为空值(null|空串|空数组|空集合)则取default值"1" .withDefault(ProductBaseInfo::getProductType, 1) //疏忽productBase实例中对应字段的值,只取override值"0" .withOverride(ProductBaseInfo::getAuditStatus, 0) .withOverride(ProductBaseInfo::getOnlineStatus, 0) .withOverride(ProductBaseInfo::getUpdateTime, DateTimeUtils.formatNow()) .build();productBaseInfoMapper.updateById(productBase.getProductId(), updateColumns1);//实现了畛域实体的identity()办法则productBase.identity()与productBase.getProductId()是等效的//productBaseInfoMapper.updateById(productBase.identity(), updateColumns);//依据条件更新Map<String,Object> updateColumns2 = MapLambdaBuilder.<ProductBaseInfo>ofEmpty() .withOverride(ProductBaseInfo::getOnlineStatus, 0) .withOverride(ProductBaseInfo::getUpdateTime, DateTimeUtils.formatNow()) .build();QueryCriteria<ProductBaseInfo> updateCriteria2 = LambdaQueryCriteria.ofSupplier(ProductBaseInfo::new) .eq(ProductBaseInfo::getProductType, 1) .in(ProductBaseInfo::getAuditStatus, 0, 1) .limit(5);productBaseInfoMapper.updateByCriteria(updateCriteria2, updateColumns2);//批量更新List<ProductSaleStock> productSaleStocks = ...;String nowTime = DateTimeUtils.formatNow();productSaleStockMapper.batchUpdate(productSaleStocks, productSaleStock -> { Map<String,Object> updateColumns = MapLambdaBuilder.of(productSaleStock) .withOverride(ProductSaleStock::getSellPrice, productSaleStock.getSellPrice() - productSaleStock.getSellPrice() % 100) .withOverride(ProductSaleStock::getUpdateTime, nowTime) .build(); //new一个联结主键实例 ID productSaleStockId = new ID() .addKey(ProductSaleStock::getProductId, productSaleStock.getProductId()) .addKey(ProductSaleStock::getProductId, productSaleStock.getSpecNo()); productSaleStockMapper.updateById(productSaleStockId, updateColumns); //或者实现了畛域实体的identity()办法,则能够如下间接调用 //productSaleStockMapper.updateById(productSaleStock.identity(), updateColumns);});查问操作//依据ID查ProductBaseInfo productBase1 = productBaseInfoMapper.selectById(1L);ProductBaseInfo productBase2 = productBaseInfoMapper.selectById(10L, new QueryColumns(ProductBaseInfo::getProductId, ProductBaseInfo::getProductName, ProductBaseInfo::getAuditStatus, ProductBaseInfo::getOnlineStatus));ID id = new ID().addKey(ProductSaleSpec::getProductId, 1L).addKey(ProductSaleSpec::getSpecNo, "101");ProductSaleSpec productSaleSpec = productSaleSpecMapper.selectById(id);//依据多个ID查问List<ProductBaseInfo> productBases = productBaseInfoMapper.selectListByIds(Arrays.asList(5L, 6L, 7L, 8L, 9L));//依据多个联结主键查问实体对象列表List<ID> ids = new ArrayList<>();ids.add(new ID().addKey(ProductSaleSpec::getProductId, 1L).addKey(ProductSaleSpec::getSpecNo, "101"));ids.add(new ID().addKey(ProductSaleSpec::getProductId, 1L).addKey(ProductSaleSpec::getSpecNo, "102"));ids.add(new ID().addKey(ProductSaleSpec::getProductId, 1L).addKey(ProductSaleSpec::getSpecNo, "103"));List<ProductSaleSpec> productSaleSpecs = productSaleSpecMapper.selectListByIds(ids); - ==> Preparing: SELECT product_id AS productId, spec_no AS specNo, spec_name AS specName, spec_index AS specIndex, remark AS remark, DATE_FORMAT(create_time, '%Y-%m-%d %T') AS createTime, DATE_FORMAT(update_time, '%Y-%m-%d %T') AS updateTime FROM t_product_sale_spec WHERE (product_id = ? AND spec_no = ?) OR (product_id = ? AND spec_no = ?) OR (product_id = ? AND spec_no = ?) - ==> Parameters: 1(Long), 101(String), 1(Long), 102(String), 1(Long), 103(String) - <== Total: 2//依据条件查问QueryCriteria<ProductSaleSpec> queryCriteria1 = LambdaQueryCriteria.ofSupplier(ProductSaleSpec::new) .eq(ProductSaleSpec::getProductId, 1L) .eq(ProductSaleSpec::getSpecNo, "101");ProductSaleSpec productSaleSpec = productSaleSpecMapper.selectByCriteria(queryCriteria1);ProductSaleStock queryRequest1 = ...;QueryCriteria<ProductSaleStock> queryCriteria2 = LambdaQueryCriteria.of(queryRequest1) .eq(ProductSaleStock::getProductId) .likeRight(ProductSaleStock::getSpecNo) .between(ProductSaleStock::getStock, queryRequest1.getMinStock(), queryRequest1.getMaxStock()) .orderBy(OrderBy.desc(ProductSaleStock::getSellPrice));List<ProductSaleStock> productStocks = productSaleStockMapper.selectListByCriteria(queryCriteria2);QueryCriteria<ProductBaseInfo> queryCriteria3 = LambdaQueryCriteria.of(queryRequest2) .and(nestedCriteria -> nestedCriteria.like(ProductBaseInfo::getProductName, "华为") .or().like(ProductBaseInfo::getProductName, "HUAWEI")) .eq(ProductBaseInfo::getProductType) .eq(ProductBaseInfo::getOnlineStatus) .in(ProductBaseInfo::getAuditStatus, queryRequest.getAuditStatuses().toArray()) .orderBy(OrderBy.desc(ProductBaseInfo::getCreateTime)) .dynamic(true); //主动过滤掉为空值(null|空串|空数组|空集合)的查问参数List<ProductBaseInfo> productBases1 = productBaseInfoMapper.selectListByCriteria(queryCriteria3);//分页查问1Page page = Page.of(1, 10);QueryCriteria<ProductBaseInfo> queryCriteria4 = LambdaQueryCriteria.of(queryRequest) .likeRight(ProductBaseInfo::getProductName) .eq(ProductBaseInfo::getProductType) .eq(ProductBaseInfo::getOnlineStatus) .in(ProductBaseInfo::getAuditStatus, queryRequest.getAuditStatuses().toArray()) .orderBy(page.getOrderBys()) .dynamic(true); //主动过滤掉为空值(null|空串|空数组|空集合)的查问参数(条件)List<ProductBaseInfo> productBases2 = productBaseInfoMapper.selectPageListByCriteria(queryCriteria4, new RowBounds(page.offset(), page.limit()));//设置总记录数page.setTotalRowCount(productBaseInfoMapper.selectPageCountByCriteria(queryCriteria4));//分页查问2(等效与下面)Page page = Page.of(2, 10);List<ProductBaseInfo> productBases2 = EntityMapperHelper.selectEntityObjectListByPage(productBaseInfoMapper, queryCriteria4, page);删除操作//依据ID删除productBaseInfoMapper.deleteById(2L);productExtraInfoMapper.deleteById(2L);//依据条件删除QueryCriteria<ProductSaleSpec> queryCriteria1 = LambdaQueryCriteria.ofSupplier(ProductSaleSpec::new) .eq(ProductSaleSpec::getProductId, 2L) .limit(5);productSaleSpecMapper.deleteByCriteria(queryCriteria1);更多示例请见:https://github.com/penggle/my...个性及限度反对繁多主键或联结主键,繁多主键时主键策略反对:IDENTITY(数据库自增的),SEQUENCE(基于序列的),NONE(无,客户端本人设置主键) ...

May 3, 2022 · 5 min · jiezi

关于mybatis:MyBatis源码学习笔记一-初遇篇

这个系列的文章的开篇《当咱们说起看源码时,咱们是在看什么》在去年十月份就开始了,明天开始填这个系列的坑。MyBatis是我接触的第一个ORM框架,也是我目前最为相熟的ORM框架,对它始终停留在用的阶段,明天尝试来看MyBatis的外部结构。如果还不会MyBatis的,能够先去看下《伪装是小白之重学MyBatis(一)》。那该如何看源码呢?我是把MyBatis的源码下载下来, 茫无目标的看?这会不会迷失在源码中呢,我记得我刚到我以后这家公司的时候,看代码就是一个一个办法的看,而后感觉很头疼,也没看懂最初再做什么。前面反思了一下,其实应该关注宏观的流程,就是这个代码实现了什么性能,这些代码都是为了实现这个性能,不用每一个办法都一行一行的看,以办法为单位去看,这个办法从整体上来看做了什么样的事件,先不用过多的去关注外部的实现细节。这样去看对代码大略心里就无数了。同样的在MyBatis这里,这也是我第一个特地认真钻研的代码,所以MyBatis系列的第一篇,咱们先从宏观上看其实现,在前面的过程中缓缓补全其细节。本篇的主线是咱们在xml中写的增删改查语句到底是怎么被执行的。 参阅了很多MyBatis源码的材料,MyBatis的整体架构能够分为三层: 接口层: SqlSession 是咱们平时与MyBatis实现交互的外围接口(包含后续整合SpringFramework用到的SqlSessionTemplte)核心层: SqlSession执行的办法,底层须要通过配置文件的解析、SQL解析,以及执行SQL时的参数映射、SQL执行、后果集映射,另外还有交叉其中的扩大插件。反对层: 核心层的性能实现,是基于底层的各个模块,独特协调实现的。搭建MyBatis的环境搭建MyBatis的环境在《伪装是小白之重学MyBatis(一)》曾经讲过了,这里只简略在讲一下: 引入Maven依赖<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.5</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.30</version> </dependency>而后来一张表CREATE TABLE `student` ( `id` int(11) NOT NULL COMMENT '惟一标识', `name` varchar(255) , `number` varchar(255) , `money` int(255) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8mb4;来个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> <!--加载配置文件--> <properties resource="jdbc.properties"/> <!--指定默认环境, 个别状况下,咱们有三套环境,dev 开发 ,uat 测试 ,prod 生产 --> <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/studydatabase?characterEncoding=utf-8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <!--设置扫描的xml,org/example/mybatis是包的全类名,StudentMapper.xml会讲--> <mappers> <!--设置扫描的xml,org/example/mybatis是包的全类名,这个BlogMapper.xml会讲 <package name = "org.example.mybatis"/> <!-- 包下批量引入 单个注册 --> <mapper resource="org/example/mybatis/StudentMapper.xml"/> </mappers> </mappers></configuration>来个Student类public class Student { private Long id; private String name; private String number; private String money; // 省略get set 函数}来个Mapper.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 = "org.example.mybatis.StudentMapper"> <select id = "selectStudent" resultType = "org.example.mybatis.Student"> SELECT * FROM STUDENT </select></mapper>来个接口public interface StudentMapper { List<Student> selectStudent();}日志配置文件log4j.rootCategory=debug, CONSOLE# Set the enterprise logger category to FATAL and its only appender to CONSOLE.log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE# CONSOLE is set to be a ConsoleAppender using a PatternLayout.log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppenderlog4j.appender.CONSOLE.Encoding=UTF-8log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayoutlog4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30开始查问之旅public class MyBatisDemo { public static void main(String[] args) throws Exception { Reader reader = Resources.getResourceAsReader("conf.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); SqlSession sqlSession = sqlSessionFactory.openSession(); StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class); List<Student> studentList = studentMapper.selectStudent(); studentList.forEach(System.out::println); }}执行之后就能够在控制台看到如下输入了: ...

April 30, 2022 · 5 min · jiezi

关于mybatis:Mybatis-手撸专栏第2章创建简单的映射器代理工厂

作者:小傅哥博客:https://bugstack.cn 积淀、分享、成长,让本人和别人都能有所播种!一、前言焦急和快,是最大的阻碍! 慢下来,慢下来,只有慢下来,你能力看到更全的信息,能力学到更扎实的技术。而那些满足你快的短篇内容尽管有时候更抓眼球,但也容易把人在技术学习上带偏,总想着越快越好。 在小傅哥编写技术文章的过程中,也会遇到这样的状况,不少读者更喜爱看;一个系列内容的结尾、一段成长故事的分享、一天成为架构的秘籍。当然我也能了解这种喜爱,毕竟大多数人都喜爱走捷径,就像冬天买了静止健身配备,夏天过来了还没有拆封。 好了,接下来咱们干闲事! 二、指标在你能浏览这篇文章之时,我置信你曾经是一个 Mybatis ORM 框架工具应用的熟练工了,那你是否分明这个 ORM 框架是怎么屏蔽咱们对数据库操作的细节的? 比方咱们应用 JDBC 的时候,须要手动建设数据库链接、编码 SQL 语句、执行数据库操作、本人封装返回后果等。但在应用 ORM 框架后,只须要通过简略配置即可对定义的 DAO 接口进行数据库的操作了。 那么本章节咱们就来解决 ORM 框架第一个关联对象接口和映射类的问题,把 DAO 接口应用代理类,包装映射操作。 三、设计通常如果能找到大家所在事件的共性内容,具备对立的流程解决,那么它就是能够被凝聚和提炼的,做成通用的组件或者服务,被所有人进行应用,缩小反复的人力投入。 而参考咱们最开始应用 JDBC 的形式,从连贯、查问、封装、返回,其实都一个固定的流程,那么这个过程就能够被提炼以及封装和补全大家所须要的性能。 当咱们来设计一个 ORM 框架的过程中,首先要思考怎么把用户定义的数据库操作接口、xml配置的SQL语句、数据库三者分割起来。其实最适宜的操作就是应用代理的形式进行解决,因为代理能够封装一个简单的流程为接口对象的实现类,设计如图 2-1: 首先提供一个映射器的代理实现类 MapperProxy,通过代理类包装对数据库的操作,目前咱们本章节会先提供一个简略的包装,模仿对数据库的调用。之后对 MapperProxy 代理类,提供工厂实例化操作 MapperProxyFactory#newInstance,为每个 IDAO 接口生成代理类。这块其实用到的就是一个简略工厂模式接下来咱们就依照这个设计实现一个简略的映射器代理操作,编码过程比较简单。如果对代理常识不相熟能够先补充下。 四、实现1. 工程构造mybatis-step-01└── src ├── main │ └── java │ └── cn.bugstack.mybatis.binding │ ├── MapperProxy.java │ └── MapperProxyFactory.java └── test └── java └── cn.bugstack.mybatis.test.dao ├── dao │ └── IUserDao.java └── ApiTest.java工程源码:https://t.zsxq.com/bmqNFQ7 ...

March 31, 2022 · 2 min · jiezi

关于mybatis:MyBatis

一、 二、

March 29, 2022 · 1 min · jiezi

关于mybatis:Mybatis框架小总结快速精通Mybatis框架

一、Mybatis介绍 MyBatis是一个反对一般 SQL查问,存储过程和高级映射的优良长久层框架。MyBatis打消了简直所有的JDBC代码和参数的手工设置以及对后果集的检索封装。MyBatis能够应用简略的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,一般的Java对象)映射成数据库中的记录。 相干视频推送:https://www.bilibili.com/vide... 二、mybatis疾速入门2.1、筹备开发环境 1、创立测试项目,一般java我的项目或者是JavaWeb我的项目均可,如下图所示: 2、增加相应的jar包 【 mybatis 】        mybatis-3.1.1.jar 【MYSQL驱动包】\ mysql-connector-java-5.1.7-bin.jar 3、创立数据库和表,针对MySQL数据库 SQL脚本如下: create database mybatis;use mybatis;CREATE TABLE users(id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20), age INT);INSERT INTO users(NAME, age) VALUES('孤傲苍狼', 27);INSERT INTO users(NAME, age) VALUES('白虎神皇', 27);将SQL脚本在MySQL数据库中执行,实现创立数据库和表的操作,如下: 到此,后期的开发环境筹备工作全副实现。 2.2、应用MyBatis查问表中的数据 1、增加Mybatis的配置文件conf.xml 在src目录下创立一个conf.xml文件,如下图所示: conf.xml文件中的内容如下: <?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" /> <property name="username" value="root" /> <property name="password" value="XDP" /> </dataSource> </environment> </environments></configuration>2、定义表所对应的实体类, 如下图所示: ...

March 22, 2022 · 2 min · jiezi

关于mybatis:透过PageHelper看Mybatis插件机制

一、startPage做了什么PageHelper.startPage(1,20);这是PageHelper举荐的应用形式,后续的第一个查询方法会分页。 察看这个办法的外部逻辑 public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count) { // 封装成page对象 Page<E> page = new Page<E>(pageNum, pageSize, count); // == 将page对象存在`PageMethod#LOCAL_PAGE`——这是一个ThreadLocal setLocalPage(page); return page;}二、PageHelper如何与Mybatis建立联系的?正是通过mybatis的插件机制plugin,入口在executor创立局部。 org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSession()org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSourceorg.apache.ibatis.session.Configuration#newExecutor(org.apache.ibatis.transaction.Transaction, org.apache.ibatis.session.ExecutorType){ // == 过滤器链对executor做封装 executor = (Executor) interceptorChain.pluginAll(executor);}察看InterceptorChain interceptorChain构造: class InterceptorChain { // ## 1.拦截器 private final List<Interceptor> interceptors = new ArrayList<>(); public Object pluginAll(Object target) { for (Interceptor interceptor : interceptors) { // ## 2.包装 target = interceptor.plugin(target); } return target; }1.拦截器被@Intercepts注解润饰的类就是拦截器,也就是所谓的插件。 ...

March 3, 2022 · 2 min · jiezi

关于mybatis:Mybatis的where标签竟然还有这么多不知道的

背景在上篇文章,咱们系统地学习了where 1=1 相干的知识点,大家能够回看《不要再用where 1=1了!有更好的写法!》这篇文章。文章中波及到了Mybatis的代替计划,有好学的敌人在评论区有敌人问了基于Mybatis写法的问题。 于是,就有了这篇文章。本篇文章会将Mybatis中where标签的根本应用模式、小技巧以及容易踩到的坑进行总结梳理,不便大家更好地实际使用d 原始的手动拼接在不应用Mybatis的where标签时,咱们通常是依据查问条件进行手动拼接,也就是用到了下面提到的where 1=1的形式,示例如下: <select id="selectSelective" resultType="com.secbro.entity.User"> select * from t_user where 1=1 <if test="username != null and username != ''"> and username = #{username} </if> <if test="idNo != null and idNo != ''"> and id_no = #{idNo} </if> </select>这种形式次要就是为了防止语句拼接谬误,呈现相似如下的谬误SQL: select * from t_user where and username = 'Tom' and id = '1001';select * from t_user where and id = '1001';当增加上1=1时,SQL语句便是正确的了: select * from t_user where 1=1 and username = 'Tom' and id = '1001';select * from t_user where 1=1 and id = '1001';这个咱们之前曾经提到过,多少对MySQL数据库的有肯定的压力。因为1=1条件的优化过滤是须要MySQL做的。如果可能将这部分放到应用程序来做,就缩小了MySQL的压力。毕竟,应用程序是能够轻易地横向扩大的。 ...

March 3, 2022 · 2 min · jiezi

关于mybatis:mybatis框架上主流程分析

// # 1.读取配置文件InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");// # 2.创立SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);// # 3.通过sqlSessionFactory创立SqlSessiontry (SqlSession session = sqlSessionFactory.openSession()) { // # 4.通过SqlSession获取Mapper,并查问 BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = mapper.selectBlog(101);}以上是Mybatis官网的demo,这次DB查问操作根本分成了上述4个步骤。 那么问题来了:在一次DB查问过程,mybatis框架具体做了什么? 间接给出论断: 1.读取mybatis-config.xml并解析,将全副配置信息和各种默认配置加载到Configuration中,蕴含:数据源信息(分装在Environment)、类型处理器、类型别名、mapper代理工厂等。Configuration是SqlSessionFactory的重要属性。 2.通过SqlSessionFactory创立transaction、executor、sqlSession。 3.通过sqlSession获取mapper,实质是通过mapper代理工厂创立mapper代理。mapper的crud办法理论执行的是MapperProxy的相干办法。在这些办法中,sql会交由executor执行,而executor最终会调用jdbc的statement。 接下来通过源码剖析demo中的四步。 一、读取配置文件// == A.mybatis配置文件转换成streamInputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");配置文件读取局部没什么可说的,无非把File转换成IO流。 咱们把眼光聚焦于mybatis-config.xml文件自身。 <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="mapper/BlogMapper.xml"/> </mappers></configuration>能够看到,最外层是一个<configuration>标签,外面可退出很多配置,如: properties(属性)settings(设置)typeAliases(类型别名)typeHandlers(类型处理器)objectFactory(对象工厂)plugins(插件)environments(环境配置) environment(环境变量) transactionManager(事务管理器)dataSource(数据源)databaseIdProvider(数据库厂商标识)mappers(映射器)理解这些就能够了,前面几步才是重点。 二、创立SqlSessionFactory// == B.初始化Configuration,并加载各类默认配置(次要是类型转换器和别名映射)SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);org.apache.ibatis.session.SqlSessionFactoryBuilder#build(java.io.InputStream)org.apache.ibatis.session.SqlSessionFactoryBuilder#build(java.io.InputStream, java.lang.String, java.util.Properties)public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { // ## 1.解析 mybatis-config.xml,同时创立 Configuration 对象 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); // ## 2.解析XML,最终返回一个 DefaultSqlSessionFactory return build(parser.parse());}1.解析 mybatis-config.xmlprivate XMLConfigBuilder(XPathParser parser, String environment, Properties props) { // 构造函数实现了Configuration的初始化,并将configuration的两个重要属性传递过去 super(new Configuration()); ⬇⬇⬇⬇⬇ this.configuration = configuration; this.typeAliasRegistry = this.configuration.getTypeAliasRegistry(); this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry(); ⬆⬆⬆⬆⬆ super(new Configuration());}察看传递过去的两个属性 ...

February 28, 2022 · 2 min · jiezi

关于mybatis:重磅升级-尚硅谷MyBatis新版视频教程发布

摘要:总有世间一两风,填我十万八千梦。 人是这样的—— 一旦有了对他人的期待, 就可能接受期待带给你的苦楚。 实在的世界很残暴, 永远不要把期待放在他人身上, 因为他人没有任务要实现你的期待。 除非…… 这个“他人”是尚硅谷! 总有世间一两风,填我十万八千梦。 泛滥谷粉期盼已久, 神超老师闭门狂撸, 等了良久终于等到明天, 盼了良久终于把梦实现: 尚硅谷MyBatis新版视频教程公布! 重磅降级 | 尚硅谷MyBatis新版视频教程公布他, 江湖上人称神超。 烫伤之后去搓澡,腿摔折了撑杆跳, 尚硅谷驰名狠人: “感觉我帅的扣1, “感觉佟刚老师帅的扣眼珠子。” 他, 先谷粉之忧而忧,后谷粉之乐而乐。 整点俄罗斯的小鸟伏特加, 咔咔咔就是一通疯狂输入, 去年8月他发了SpringMVC新版视频, 明天他又发了MyBatis新版视频。 “五行阴阳开天地,纵横捭阖定生息。 “梭哈是一种智慧,听懂掌声!” 神超最近心烦技痒欲逞所长, 还会带来什么惊喜敬请期待…… MyBatis 是一款风行的长久层框架,它反对定制化SQL、存储过程以及高级映射。MyBatis 防止了简直所有的JDBC代码和手动设置参数以及获取后果集,能够应用简略的XML或注解来配置和映射原生信息,将接口和Java的POJOs(Plain Ordinary Java Object,一般的 Java对象)映射成数据库中的记录。 本套视频教程内容涵盖:MyBatis框架搭建、MyBatis配置文件以及映射文件解说及编写、MyBatis获取参数值的形式、MyBatis中各种查问性能、MyBatis自定义映射、MyBatis动静SQL、MyBatis缓存机制、MyBatis逆向工程、MyBatis分页插件等。 教程以MySQL数据库为案例,应用Idea作为IDE,应用Maven作为构建工具,应用MyBatis 3.5.7版本解说。本套教程的学习与Spring和SpringMVC没有先后顺序,只需具备JDBC根底即可。 MyBatis新版视频教程简介https://www.bilibili.com/vide... 关注尚硅谷B站官网账号,一手最新视频教程领先看! 教程具体目录: 01.MyBatis教程简介02.MyBatis的历史03.MyBatis的个性04.MyBatis的下载05.MyBatis和其余长久化层技术的比照06.搭建MyBatis框架之开发环境07.搭建MyBatis框架之创立maven工程08.搭建MyBatis框架之创立MyBatis的外围配置文件09.搭建MyBatis框架之创立mapper接口10.搭建MyBatis框架之创立MyBatis的映射文件11.搭建MyBatis框架之测试增加性能12.搭建MyBatis框架之优化性能13.搭建MyBatis框架之测试批改和删除性能14.搭建MyBatis框架之测试查问性能15.MyBatis外围配置文件之environment16.MyBatis外围配置文件之properties17.MyBatis外围配置文件之typeAliases18.MyBatis外围配置文件之mappers19.思考:映射文件中的SQL该如何拼接20.在idea中设置外围配置文件的模板21.在idea中设置映射文件的模板22.封装SqlSessionUtils工具类并测试性能23.MyBatis获取参数值的两种形式#{}和${}24.MyBatis获取参数值的各种状况(1)25.MyBatis获取参数值的各种状况(2)26.MyBatis获取参数值的各种状况(3)27.MyBatis获取参数值的各种状况(4)28.MyBatis获取参数值的各种状况(5)29.@Param源码解析30.MyBatis各种查问性能(1)31.MyBatis各种查问性能(2)32.MyBatis各种查问性能(3)33.MyBatis各种查问性能(4)34.MyBatis解决含糊查问35.MyBatis解决批量删除36.MyBatis解决动静设置表名37.MyBatis获取增加性能自增的主键38.搭建MyBatis框架39.通过字段别名解决字段名和属性名的映射关系40.通过全局配置mapUnderscoreToCamelCase解决字段名和属性名的映射关系41.通过resultMap解决字段名和属性名的映射关系42.通过级联属性赋值解决多对一的映射关系43.通过association解决多对一的映射关系44.通过分步查问解决多对一的映射关系45.提早加载46.通过collection解决一对多的映射关系47.通过分步查问解决一对多的映射关系48.动静SQL简介49.动静SQL之if标签50.动静SQL之where标签51.动静SQL之trim标签52.动静SQL之choose、when、otherwise53.动静SQL之foreach标签(1)54.动静SQL之foreach标签(2)55.动静SQL之sql标签56.MyBatis的一级缓存57.使一级缓存生效的四种状况58.MyBatis的二级缓存59.MyBatis二级缓存相干配置60.MyBatis缓存查问的程序61.MyBatis整合第三方缓存EHCache62.MyBatis逆向工程之清晰简洁版63.MyBatis逆向工程之豪华尊享版(1)64.MyBatis逆向工程之豪华尊享版(2)65.MyBatis的分页插件简介66.MyBatis分页插件的应用 尚硅谷Java视频精选 JavaWeb新版视频教程 Docker与微服务实战视频教程 SpringMVC新版视频教程 微信领取实战视频教程 云原生实战视频教程 RocketMQ视频教程 RabbitMQ视频教程 JVM性能监控与调优视频教程 Redis6新版视频教程 尚融宝我的项目视频教程 猫有一种特点: 不论你有没有钱, 它一样看不起你。 尚硅谷有一种风格: 无论你是不是白嫖, 咱们一样实力宠粉! 我替大家伙儿和神超表个白: 我是那么喜爱你…… 行尽千山,归处是你。 望尽星辰,梦里是你。 书尽泛黄,扉页是你。 ...

February 24, 2022 · 1 min · jiezi

关于mybatis:Hibernate-和-MyBatis-哪个更好用

因为编程思维与数据库的设计模式不同,生出了一些 ORM 框架。外围都是将关系型数据库和数据转成对象型。以后风行的计划有 Hibernate 与 myBatis。两者各有优劣。竞争强烈,其中一个比拟重要的思考的中央就是性能。因而笔者通过各种试验,测出两个在雷同情景下的性能相干的指数,供大家参考。 测试指标以下测试须要确定几点内容:性能差别的场景;性能不在同场景下差别比;找出各架框优劣,各种状况下的体现,实用场景。 测试思路测试总体分成:单表插入,关联插入,单表查问,多表查问。测试分两轮,同场景下默认参数做一轮,调优做强一轮,横纵比照剖析了。测试中尽保障输入输出的一致性。样本量尽可能大,达到 10 万级别以上,缩小统计误差。 测试提纲具体的场景状况下插入测试 1:10 万条记录插入。查问测试 1:100 万数据中单表通过 id 查问 100000 次,无关联字段。查问测试 2:100 万数据中单表通过 id 查问 100000 次,输入关联对象字段。查问测试 3:100 万*50 万关联数据中查问 100000 次,两者输入雷同字段。 筹备数据库:mysql 5.6 表格设计:twitter:推特 CREATE TABLE `twitter` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `add_date` datetime DEFAULT NULL, `modify_date` datetime DEFAULT NULL, `ctx` varchar(255) NOT NULL, `add_user_id` bigint(20) DEFAULT NULL, `modify_user_id` bigint(20) DEFAULT NULL, PRIMARY KEY (`id`), KEY `UPDATE_USER_FORI` (`modify_user_id`), KEY `ADD_USER_FORI` (`add_user_id`), CONSTRAINT `ADD_USER_FORI` FOREIGN KEY (`add_user_id`) REFERENCES `user` (`id`) ON DELETE SET NULL, CONSTRAINT `UPDATE_USER_FORI` FOREIGN KEY (`modify_user_id`) REFERENCES `user` (`id`) ON DELETE SET NULL) ENGINE=InnoDB AUTO_INCREMENT=1048561 DEFAULT CHARSET=utf8user: 用户 ...

February 18, 2022 · 4 min · jiezi

关于mybatis:mybatis如何防止SQL注入

sql注入产生的工夫,sql注入产生的阶段在sql预编译阶段,当编译实现的sql不会产生sql注入 一、采纳jdbc操作数据时候 String sql = "update ft_proposal set id = "+id; PreparedStatement prepareStatement = conn.prepareStatement(sql); prepareStatement.executeUpdate();复制代码 preparedStatement 预编译对象会对传入sql进行预编译,那么当传入id 字符串为 "update ft_proposal set id = 3;drop table ft_proposal;" 这种状况下就会导致sql注入删除ft_proposal这张表。 如何避免sql注入,首先将要执行sql进行预编译,而后在将占位符进行替换 String sql = "update ft_proposal set id = ?"PreparedStatement ps = conn.preparedStatement(sql);ps.setString(1,"2");ps.executeUpdate();复制代码解决应用预编译语句之外,java培训另一种实现形式能够采纳存储过程,存储过程其实也是预编译的,存储过程是sql语句的汇合,将所有预编译的sql 语句编译实现后,存储在数据库上,因为存储过程比拟死板个别不采纳这种形式进行解决。 二、mybatis是如何解决sql注入的? 假如mapper.xml文件中sql查问语句为: <select id="findById" resultType="String"> select name from user where id = #{userid};</select>复制代码对应的接口为: public String findById(@param("userId")String userId);复制代码当传入的参数为3;drop table user; 当咱们执行时能够看见打印的sql语句为: select name from usre where id = ?; ...

February 15, 2022 · 1 min · jiezi

关于mybatis:mybatis之注解实现机制

咱们在应用 mybatis的时候,少数状况下都是创立一个对应 mapper 的 xml 文件来写 sql 语句,这种形式也是官网举荐并且是最灵便的形式。但其实 mybatis 也反对通过注解的形式来实现 sql 语句。本篇文章就是聊聊 mybatis 是如何应用注解形式来实现 sql 执行的。 知识点什么是注解如何应用实现原理什么是注解翻译过去可能很多人不分明,翻译回去就是 Annotation。咱们平时在代码中肯定用到很多注解,特地是 springboot 我的项目,看上面的例子你就明确了 @SpringBootApplicationpublic class MybatisAnalyzeApplication { public static void main(String[] args) { SpringApplication.run(MybatisAnalyzeApplication.class, args); }}这是非常简单的一个 springboot 启动类,这个@SpringBootApplication就是注解。 如何应用mybatis 注解形式的应用非常简单,间接在你定义的 Mapper 接口对应的办法上加一个注解就能够了,间接上代码: @Repositorypublic interface UserInfoMapper { UserInfo selectById(int id); @Select("select * from user_info where user_name = #{userName}") List<UserInfo> select(String userName, String nickName); int insert(UserInfo userInfo); int update(int id, String nickName);}能够看到UserInfoMapper接口中的select办法下面有一个@Select的注解,这样就完了。其余几个没有加注解的办法,还是须要定义 xml 文件(注解形式和 xml 形式是能够混用的),须要留神的是 xml 文件中不能再定义曾经加过注解的办法,否走会抛出异样。同样的,对于增、改、删操作,加上注解@Insert、@Update、@Delete即可。 ...

February 10, 2022 · 1 min · jiezi

关于mybatis:Mybatis-常用注解中的-SQL-注入

MyBatis3提供了新的基于注解的配置。次要在MapperAnnotationBuilder中,定义了相干的注解: public MapperAnnotationBuilder(Configuration configuration, Class<?> type) { ... sqlAnnotationTypes.add(Select.class); sqlAnnotationTypes.add(Insert.class); sqlAnnotationTypes.add(Update.class); sqlAnnotationTypes.add(Delete.class); ...... sqlProviderAnnotationTypes.add(SelectProvider.class); sqlProviderAnnotationTypes.add(InsertProvider.class); sqlProviderAnnotationTypes.add(UpdateProvider.class); sqlProviderAnnotationTypes.add(DeleteProvider.class);}增删改查占据了绝大部分的业务操作,通过注解不在须要配置繁冗的xml文件,越来越多的sql交互均通过注解来实现。从MapperAnnotationBuilder能够看到Mybatis提供了以下相干的注解:@Select@Insert@Update@Delete@SelectProvider@InsertProvider@UpdateProvider@DeleteProvider例如如下例子,应用@Select注解间接编写SQL实现数据查问: @Mapperpublic interface UserMapper { @Select("select * from t_user") List<User> list();}应用相似@SelectProvider高级注解能够指定某个工具类的办法来动静编写SQL,以应答简单的业务需要。以@SelectProvider 为例,查看具体的实现,次要蕴含两个注解属性,其中type示意工具类,method 示意工具类的某个办法,用于返回具体的SQL: @Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface InsertProvider { // 用于指定获取 sql 语句的指定类 Class<?> type(); // 指定类中要执行获取 sql 语句的办法 String method();}应用办法如下,在ProjectSql类的getContentByProjectIds办法定义相干的sql即可,sql的定义能够通过org.apache.ibatis.jdbc.SQL来疾速实现:@SelectProvider(type = ProjectSql.class, method = "getContentByProjectIds")List<Integer> getContentByProjectIds(List<Integer> projectIds); 常见注入场景2.1一般注解实际上跟xml配置中对应的标签语法是一样的(例如@Select对应<select>标签),所以注入场景也是相似的。在Mybatis中,#的作用次要是替换预编译语句(PrepareStatement)中的占位符?,$是间接的SQL拼接。以like含糊查问 为例子:例如如下例子:跟xml配置一样,like含糊查问间接应用#预编译的形式进行注解的话会触发异样,所以很多时候间接应用$进行注解: @Select("SELECT id, name, age, email FROM user where name like '${name}'")List<User> queryUserByName(@Param("name") String name);那么此时name前端用户可控的话,将导致SQL注入危险。图片查看sql日志,胜利执行1/0触发sql error,阐明注入胜利: ...

February 9, 2022 · 2 min · jiezi

关于mybatis:mybatis之数据源连接池

本篇来介绍一下 mybatis 的数据源连接池相干内容,咱们平时在我的项目中应用的数据源连接池有Hikaricp、Druid、c3p0等等,大多数状况下咱们应用 mybatis 的时候都是集成内部数据源连接池来应用,其实 mybatis 本身也实现了简略的数据源连接池。 知识点什么是连接池如何应用 mybatis 连接池mybatis 连接池的实现原理什么是连接池对于连接池的概念,我置信大家都比较清楚,对于很新很新的新人,这里还是简略的介绍一下。简略的说就是一个容器里放了很多个连贯,咱们须要连贯就去容器里拿,用完了就还回去,容器负责对所有连贯的治理。画了个图,能够感受一下: 如果还不能了解,就把连接池设想成一个外包公司,外面有很多员工,里面有我的项目须要就派人进来,我的项目完结了人就回来,公司就是一个池子,员工就是每个连贯。 如何应用 mybatis 连接池mybatis原生形式对于 mybatis 连接池的应用,官网文档有介绍 在 dataSource 中指定 type 即可,目前反对三种内置的实现,别离为 UNPOOLED、POOLED、JNDI,这三种都是 mybatis 的内置定义的假名,会去找到理论的类型,当然咱们也能够自定义数据源工厂类来指定其余的数据源,具体实现能够参考官网。 集成 spring 形式通常咱们都是集成 srping 来应用 mybatis 的,集成了 spring 之后,以上形式就不起作用了,起因是 spring 框架中会去替换配置里的环境信息(也就是 environment 节点),此时咱们就得通过 spring 的配置形式来指定数据源,大抵须要以下两步: 1、配置数据源必填属性 <bean id="dataSource" class="org.apache.ibatis.datasource.pooled.PooledDataSource"> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </bean>2、指定 spring 数据源 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> </bean>应用 springboot 形式随着 springboot 应用地越来越多,mybatis 对应的 srpingboot 集成包也面世了,我的项目中引入以下包即可应用 <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency>当然 mybatis 的 springboot 形式在配置方面还有很多局限性,也包含咱们这次要说的应用 mybatis 自带的连接池。如果要应用 mybatis 自带的连接池,肯定要自定义一个连接池类来进行包装,也是两步: ...

February 7, 2022 · 2 min · jiezi

关于mybatis:Mybatis动态SQL

什么是动静SQL?动静SQL就是指依据不同的条件生成不同的SQL语句。 如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动静 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,须要花工夫理解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素品种,当初要学习的元素品种比原来的一半还要少。 ifchoose (when, otherwise)trim (where, set)foreachif<select id="queryBlogIF" parameterType="map" resultType="Blog"> select * from mybatis.blog where 1=1 <if test="title != null"> and title = #{title} </if> <if test="author != null"> and author = #{author} </if></select>wherewhere 元素只会在子元素返回任何内容的状况下才插入 “WHERE” 子句。若子句的结尾为 “AND” 或 “OR”,where 元素也会将它们去除。改写下面if的动静sql为: <select id="queryBlogIF" parameterType="map" resultType="Blog"> select * from mybatis.blog <where> <if test="title != null"> and title = #{title} </if> <if test="author != null"> and author = #{author} </if> </where></select>choose、when、otherwise<select id="queryBlogChoose" parameterType="map" resultType="Blog"> select * from mybatis.blog <where> <choose> <when test="title != null"> and title = #{title} </when> <when test="author != null"> and author = #{author} </when> <otherwise> and views = #{views} </otherwise> </choose> </where></select>SQL片段有的时候,咱们可能会将一些性能的局部抽取进去,不便复用!1.应用SQL标签抽取公共的局部 ...

January 26, 2022 · 1 min · jiezi

关于mybatis:mybatis之配置加载

本篇来聊以下mybatis的配置加载内容,来看下 mybatis 是如何对配置进行加载的。 知识点mybatis 原生怎么加载mybatis-spring 如何加载前言咱们平时在应用mybatis的时候,很多时候都会去定义一个xml配置文件,大略如下 <?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> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> <setting name="logImpl" value="MYLOG"/> </settings> <typeAliases> <typeAlias alias="MYLOG" type="com.example.mybatisanalyze.logger.MyloggerImpl"/> </typeAliases> <typeHandlers> <package name="com.example.mybatisanalyze.typehandler"/> </typeHandlers> <plugins> <plugin interceptor="com.example.mybatisanalyze.plugin.MyPlugin"> <property name="output" value="hello"/> </plugin> </plugins></configuration>咱们晓得该配置文件会在 mybatis 整个执行过程中失效,那么它是如何被加载的呢? mybatis 原生怎么加载mybatis 自身提供了配置加载的入口,在org.apache.ibatis.session.SqlSessionFactoryBuilder中去创立 SqlSessionFactory 的时候会先去做配置解析,所以咱们如果间接用mybatis,个别是先用SqlSessionFactoryBuilder的 build 函数来传入对应配的配置文件流,大抵应用如下 Reader reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/global_variables_defaults/mybatis-config.xml"); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props);或者 String resource = "org/apache/ibatis/submitted/association_nested/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);再来看下build里做了什么 能够看到在 build 里次要是应用org.apache.ibatis.builder.xml.XMLConfigBuilder对配置进行加载。看下 parser.parse() 逻辑 能够看到这里取解析了configuration节点,再进去看下子节点的解析逻辑 ...

January 25, 2022 · 1 min · jiezi

关于mybatis:Mybatis日志工厂

Mybatis 通过应用内置的日志工厂提供日志性能。有以下几种实现: SLF4JApache Commons LoggingLog4j 2Log4j (deprecated since 3.5.9)JDK loggingSTDOUT_LOGGING【规范】在外围配置文件mybatis-config.xml可配置日志工具,不少应用服务器(如 Tomcat 和 WebShpere)的类门路中曾经蕴含 Commons Logging,所以在这种配置环境下的 MyBatis 会把它作为日志工具。 Log4j什么是Log4j? Log4j是Apache的一个开源我的项目,通过应用Log4j,咱们能够管制日志信息输送的目的地是控制台、文件、GUI组件咱们也能够管制每一条日志的输入格局通过定义每一条日志信息的级别,咱们可能更加粗疏地管制日志的生成过程通过一个配置文件来灵便地进行配置,而不须要批改利用的代码maven导入Log4j的包<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version></dependency>log4j.properties#将等级为DEBUG的日志信息输入到console和file这两个目的地,console和file的定义在上面的代码log4j.rootLogger=DEBUG,console,file#控制台输入的相干设置log4j.appender.console = org.apache.log4j.ConsoleAppenderlog4j.appender.console.Target = System.outlog4j.appender.console.Threshold=DEBUGlog4j.appender.console.layout = org.apache.log4j.PatternLayoutlog4j.appender.console.layout.ConversionPattern=[%c]-%m%n#文件输入的相干设置log4j.appender.file = org.apache.log4j.RollingFileAppenderlog4j.appender.file.File=./log/sunfl.loglog4j.appender.file.MaxFileSize=10mblog4j.appender.file.Threshold=DEBUGlog4j.appender.file.layout=org.apache.log4j.PatternLayoutlog4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n#日志输入级别log4j.logger.org.mybatis=DEBUGlog4j.logger.java.sql=DEBUGlog4j.logger.java.sql.Statement=DEBUGlog4j.logger.java.sql.ResultSet=DEBUGlog4j.logger.java.sql.PreparedStatement=DEBUG批改外围配置文件,将log4j设置为日志的实现 <settings> <!--规范的日志工厂实现--><!-- <setting name="logImpl" value="STDOUT_LOGGING"/>--> <setting name="logImpl" value="LOG4J"/> </settings>Log4j日志 简略应用在须要应用Log4j的类中,导入包import org.apache.log4j.Logger;日志对象,参数为以后类的classstatic Logger logger = Logger.getLogger(UserDaoTest.class);日志级别logger.info("info:进入了testLog4j");logger.debug("debug:进入了testLog4j");logger.error("error:进入了testLog4j");

January 21, 2022 · 1 min · jiezi

关于mybatis:MyBatis的功能架构是怎样的

Mybatis的性能架构分为三层: (1)API接口层:提供给内部应用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接管到调用申请就会调用数据处理层来实现具体的数据处理。 (2)数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行后果映射解决等。它次要的目标是依据调用的申请实现一次数据库操作。 (3)根底撑持层:负责最根底的性能撑持,包含连贯治理、事务管理、配置加载和缓存解决,这些都是共用的货色,将他们抽取进去作为最根底的组件。为下层的数据处理层提供最根底的撑持。 二、mybatis执行流程 1.加载配置文件并初始化(SqlSession) 配置文件来源于两个中央,一个是配置文件(主配置文件conf.xml,mapper文件*.xml),一个是java代码中的正文,大数据培训将sql的配置信息加载成为一个mappedstatement对象,存储在内存之中(包含传入参数的映射配置,后果映射配置,执行的sql语句)。 2.接管调用申请 调用mybatis提供的api,传入的参数为sql的id(有namespase和具体sql的id组成)和sql语句的参数对象,mybatis将调用申请交给申请解决层。 3.解决申请 依据sql的id找到对应的mappedstatament对象。 依据传入参数解析mappedstatement对象,失去最终要执行的sql。 获取数据库连贯,执行sql,失去执行后果 Mappedstatement对象中的后果映射对执行后果进行转换解决,并失去最终的处理结果。 开释连贯资源 4.返回处理结果 关键词:大数据培训

January 21, 2022 · 1 min · jiezi

关于mybatis:Mybatis配置解析

外围配置文件MyBatis外围配置文件mybatis-config.xml蕴含了会深深影响 MyBatis 行为的设置和属性信息。 环境变量(environments)Mybatis能够配置多套环境,dev,test,prod等然而每个sqlSessionFactory实例只能抉择一种环境。Mybatis默认的事务管理器是JDBC,连接池是POOLED <environments default="dev"> <environment id="dev"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306"/> <property name="username" value="root"/> <property name="password" value="xxx"/> </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://127.0.0.1:3306"/> <property name="username" value="ro11ot"/> <property name="password" value="x11xx"/> </dataSource> </environment></environments>属性(properties)可通过properties属性来实现援用配置文件,这些属性能够在内部进行配置且可动静替换,既能够在典型的 Java 属性文件中配置,也能够在 properties 元素的子元素【db.properties】中设置。db.properties,可在外围配置文件中引入该内部文件 driver=com.mysql.jdbc.Driverurl=jdbc:mysql://127.0.0.1:3306能够间接引入内部文件,或者在其中减少一些属性配置,如果两个文件有同一个字段,优先应用内部配置文件的 <!--引入内部配置文件--><properties resource="db.properties"> <property name="username" value="root"/> <property name="password" value="1xxxxx"/></properties>类型别名(typeAliases)形式一:类型别名是为java类型设置一个短的名字,意义在于升高冗余的全限定类名书写。 <!--能够给实体类起别名--><typeAliases> <typeAlias type="com.sunfl.pojo.User" alias="User"/></typeAliases>形式二:也能够指定一个包名,MyBatis 会在包名上面搜寻须要的 Java Bean。扫描实体类的包,它的默认别名就为这个类的类名,首字母小写。 <!--能够给实体类起别名--><typeAliases> <package name="com.sunfl.pojo"/></typeAliases>在实体类比拟少的时候,应用第一种形式;如果实体类非常之多,倡议应用第二种;第一种能够DIY别名,第二种则不行,如果非要改,须要在实体类上减少注解。 @Alias("helloUser")public class User {}<select id="getUserList" resultType="helloUser"> select * from mybatis.user</select>

January 20, 2022 · 1 min · jiezi

关于mybatis:mybatis之日志框架

本篇次要来聊一下 mybatis 的日志框架,揭秘 mybtais 是如何可能集成各种不同的日志框架的。 知识点如何打印日志自定义日志实现实现原理如何打印日志咱们平时在应用 mybatis 的时候偶然会遇到一些问题,想要看下咱们执行的sql到底是怎么样的,这时就须要将 mybtais 的执行日志打印进去了,如何打印日志呢,网上材料很多,官网也给出了阐明,大略就是以下三步(以log4j2为例): 1)引入日志 jar 包 <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.14.1</version></dependency>2) 配置日志输入(如log4j2.xml) <?xml version="1.0" encoding="UTF-8"?><Configuration xmlns="http://logging.apache.org/log4j/2.0/config"> <Appenders> <Console name="stdout" target="SYSTEM_OUT"> <PatternLayout pattern="%5level [%t] - %msg%n"/> </Console> </Appenders> <Loggers> <Logger name="com.example.mybatisanalyze.mapper" level="debug"/> <Root level="info" > <AppenderRef ref="stdout"/> </Root> </Loggers></Configuration>Logger能够对某些项日志输入级别独自配置,避免输入太多。 3)mybatis 全局配置文件配置日志输入实现 <settings> <setting name="logImpl" value="LOG4J2"/> </settings>通过下面几步配置就能够打印日志了。 目前 mybatis 反对的日志实现有以下几种,看名称预计大家也晓得了 你没看错,mybatis 不反对 logback 实现!然而提供了 slf4j 实现,咱们能够基于此应用 logback,当然你也能够通过自定义日志实现类来实现。另外能够看到,3.5.9之后版本不反对 log4j 了。各种应用形式具体能够参考官网。 自定义日志实现接着咱们来看一下如何自定义一个日志实现,咱们感觉 mybatis 提供的几种形式都不适宜咱们的业务场景,那么就须要自定义了。也只须要三步: 1)定义一个日志实现类,继承org.apache.ibatis.logging.Log接口 public class MyloggerImpl implements Log { public MyloggerImpl(String clazz){ } /** * 设为true就会输入debug内容 **/ @Override public boolean isDebugEnabled() { return false; } /** * 设为true就会输入trace内容 **/ @Override public boolean isTraceEnabled() { return false; } @Override public void error(String s, Throwable throwable) { System.out.println("error2:" + s); } @Override public void error(String s) { System.out.println("error:" + s); } @Override public void debug(String s) { System.out.println("debug:" + s); } @Override public void trace(String s) { System.out.println("trace:" + s); } @Override public void warn(String s) { System.out.println("warn:" + s); }}2)mybatis 全局配置文件中注册这个日志实现类 ...

January 20, 2022 · 1 min · jiezi

关于mybatis:Mybatis入门之CRUD

xml元素namespacexml中的namespace与dao接口的包名统一idxml中的id与dao接口的办法名统一resultTypesql语句执行的返回值parameterType参数类型select编写接口//查问全副用户List<User> getUserList();编写sql语句<!--select查问语句--><select id="getUserList" resultType="com.sunfl.pojo.User"> select * from mybatis.user</select>测试@Testpublic void test(){ //取得SqlSession对象 SqlSession sqlSession = MybatisUtils.getSqlSession(); //形式一:执行SQL 举荐 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.getUserList(); //形式二:// List<User> userList = sqlSession.selectList("com.sunfl.dao.UserDao.getUserList"); for (User user : userList) { System.out.println(user); } //敞开sqlSession sqlSession.close();}insert编写接口//新增一个用户int addUser(User user);编写sql语句<insert id="addUser" parameterType="com.sunfl.pojo.User"> insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd});</insert>测试@Testpublic void addUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.addUser(new User(4, "哈哈哈", "12323")); sqlSession.commit(); sqlSession.close();}update编写接口//更新一个用户int updateUser(User user);编写sql语句<update id="updateUser" parameterType="com.sunfl.pojo.User"> update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id};</update>测试@Testpublic void updateUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.updateUser(new User(4,"嘿嘿","1111")); sqlSession.commit(); sqlSession.close();}delete编写接口//删除一个用户int deleteUser(int id);编写sql语句<delete id="deleteUser" parameterType="int"> delete from mybatis.user where id = #{id};</delete>测试@Testpublic void deleteUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.deleteUser(4); sqlSession.commit(); sqlSession.close();}

January 19, 2022 · 1 min · jiezi

关于mybatis:mybatis之缓存机制

本篇来聊一下mybatis的缓存机制,基于3.4.6版本。 知识点什么是缓存mybatis缓存缓存实现机制什么是缓存对于缓存的概念,我置信学过编程的都晓得,它次要针对的是拜访效率。咱们的程序如果去磁盘或者近程获取资源都是有耗费的,磁盘的耗费在IO这块,近程的耗费在网络这块,这里又波及到用户态和内核态的切换耗费,那怎么来缩小这些拜访呢?咱们能够把常常须要拜访的数据存到磁盘之后再复制一份到jvm内存里,对于这部分数据,咱们间接去jvm里获取,而不必去近程或者磁盘上获取,这样就进步了程序的性能,这部分内存里的数据就叫做缓存。它实质上是一种空间换工夫的性能优化形式。 mybatis缓存mybatis是一款优良的长久化框架,当然也有本人的缓存机制。这一点置信大家想想也能晓得为什么,去数据库获取数据必定是有肯定性能损耗的,那咱们就能够对于同样的sql查问操作做一些缓存,缩小数据库的拜访并进步数据获取效率。那么mybatis有哪些缓存并且要如何来应用呢? 缓存类型这里先介绍一下mybatis有哪些缓存类型。mybatis分为一级缓存和二级缓存,什么是一级,什么是二级呢? 一级缓存 mybatis 默认开启的,是基于 SqlSession 级别的缓存,也就是说同一个session中是能够对缓存做复用的,然而不同的session中,缓存就是各管各的。援用这篇文章一幅图 二级缓存二级缓存是须要咱们手动开启的,非查问类操作每次操作会清理一遍,缓存是基于 namespace 级别的(能够了解为一个mapper),多个 session 能够共用。还是援用这篇文章的图 咱们在执行一个查问操作的时候,mybatis 的执行程序是:二级缓存 -> 一级缓存 -> 数据库。 如何应用上面咱们来通过案例应用一下mybatis的缓存,看下成果。 下面说过一级缓存是默认就有的,所以咱们间接用,上代码 DefaultSqlSessionFactory sqlSessionFactory = (DefaultSqlSessionFactory)applicationContext.getBean("sqlSessionFactory"); DefaultSqlSession sqlSession = (DefaultSqlSession)sqlSessionFactory.openSession(); UserInfo userInfo = sqlSession.getMapper(UserInfoMapper.class).selectById(1); DefaultSqlSession sqlSession1 = (DefaultSqlSession)sqlSessionFactory.openSession(); UserInfo userInfo1 = sqlSession1.getMapper(UserInfoMapper.class).selectById(1);看下执行后果: 能够看到申请了两次数据库,这就合乎不同session不共享一级缓存的状况。 再改下代码 DefaultSqlSessionFactory sqlSessionFactory = (DefaultSqlSessionFactory)applicationContext.getBean("sqlSessionFactory"); DefaultSqlSession sqlSession = (DefaultSqlSession)sqlSessionFactory.openSession(); UserInfo userInfo = sqlSession.getMapper(UserInfoMapper.class).selectById(1); UserInfo userInfo1 = sqlSession.getMapper(UserInfoMapper.class).selectById(1);看下后果 能够看到就拜访了一次数据库! 咱们再来试一下二级缓存,二级缓存是须要独自配置的。有两个中央要配置,第一个是全局配置文件,这个不配默认也是true。 <?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> <settings> <setting name="cacheEnabled" value="true"/> </settings></configuration>第二个是mapper文件,只有加<cache/>标签即可(也能够是应用cache-ref来援用其余namespace的缓存),当然你能够对<cache/>做一些更具体的配置,参照官网文档 ...

January 17, 2022 · 1 min · jiezi

关于mybatis:mybatis之脚本解析器

mybatis之脚本解析器本篇次要来介绍一下 mybatis 的脚本解析性能,基于mybatis 3.4.6。 知识点什么是脚本解析器解析原理什么是脚本解析器第一眼看到脚本解析器这个说法,你必定会一脸懵逼,这百度上都搜不到啊。没错,这是我集体定义的,为什么取名叫脚本解析器呢,因为我是依据代码中来取的,基于两点起因: 1、对应的包名叫:scripting2、次要解析的是 xml 等文本内容,在我看来相当于脚本(sql语句其实也是一种脚本) 介绍完名称由来之后,再来介绍一下它到底是什么。 咱们平时在应用 Mybatis 的时候,个别只有两步: 1、定义一个接口,个别是xxxMapper,定义了一些CURD接口; 2、定义上一步 Mapper 接口对应的配置文件,个别是 xxxMapper.xml,而后在配置文件中定义各个CURD接口对应的 sql 就能够了; 在配置文件中,咱们个别都会用到动静 sql,比方 <if test="title != null"> AND title like #{title} </if>再比方 <choose> <when test="title != null"> AND title like #{title} </when> <when test="author != null and author.name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose>当然还有where、foreach等罕用的标签。这些标签显著不是 sql 自身的语法能解析的,为什么咱们却能这么用呢?说到这里想必大家曾经晓得了,这就是脚本解析器施展的作用。 解析原理在理解脚本解析器是什么后,咱们基于一个例子来看下它是怎么对脚本做解析的。先定义一个Mapper @Repositorypublic interface UserInfoMapper { List<UserInfo> select(String userName, String nickName);}再定义一个对应 UserInfoMapper.xml 文件 ...

January 10, 2022 · 1 min · jiezi

关于mybatis:jdbcType对照

1.0规范的JDBC类型:SQL数据类型JDBC类型代码规范的Java类型Oracle扩大的Java类型CHARjava.sql.Types.CHARjava.lang.Stringoracle.sql.CHARVARCHAR2java.sql.Types.VARCHARjava.lang.Stringoracle.sql.CHARLONGjava.sql.Types.LONGVARCHARjava.lang.Stringoracle.sql.CHARNUMBERjava.sql.Types.NUMERICjava.math.BigDecimaloracle.sql.NUMBERNUMBERjava.sql.Types.DECIMALjava.math.BigDecimaloracle.sql.NUMBERNUMBERjava.sql.Types.BITbooleanoracle.sql.NUMBERNUMBERjava.sql.Types.TINYINTbyteoracle.sql.NUMBERNUMBERjava.sql.Types.SMALLINTshortoracle.sql.NUMBERNUMBERjava.sql.Types.INTEGERintoracle.sql.NUMBERNUMBERjava.sql.Types.BIGINTlongoracle.sql.NUMBERNUMBERjava.sql.Types.REALfloatoracle.sql.NUMBERNUMBERjava.sql.Types.FLOATdoubleoracle.sql.NUMBERNUMBERjava.sql.Types.DOUBLEdoubleoracle.sql.NUMBERRAWjava.sql.Types.BINARYbyte[]oracle.sql.RAWRAWjava.sql.Types.VARBINARYbyte[]oracle.sql.RAWLONGRAWjava.sql.Types.LONGVARBINARYbyte[]oracle.sql.RAWDATEjava.sql.Types.DATEjava.sql.Dateoracle.sql.DATEDATEjava.sql.Types.TIMEjava.sql.Timeoracle.sql.DATETIMESTAMPjava.sql.Types.TIMESTAMPjaval.sql.Timestamporacle.sql.TIMESTAMP2.0规范的JDBC类型:SQL数据类型JDBC类型代码规范的Java类型Oracle扩大的Java类型BLOBjava.sql.Types.BLOBjava.sql.Bloboracle.sql.BLOBCLOBjava.sql.Types.CLOBjava.sql.Cloboracle.sql.CLOB用户定义的对象java.sql.Types.STRUCTjava.sql.Structoracle.sql.STRUCT用户定义的参考java.sql.Types.REFjava.sql.Reforacle.sql.REF用户定义的汇合java.sql.Types.ARRAYjava.sql.Arrayoracle.sql.ARRAYOracle扩大:SQL数据类型JDBC类型代码规范的Java类型Oracle扩大的Java类型BFILEoracle.jdbc.OracleTypes.BFILEN/Aoracle.sql.BFILEROWIDoracle.jdbc.OracleTypes.ROWIDN/Aoracle.sql.ROWIDREF CURSORoracle.jdbc.OracleTypes.CURSORjava.sql.ResultSetoracle.jdbc.OracleResultSetTIMESTAMPoracle.jdbc.OracleTypes.TIMESTAMPjava.sql.Timestamporacle.sql.TIMESTAMPTIMESTAMP WITH TIME ZONEoracle.jdbc.OracleTypes.TIMESTAMPTZjava.sql.Timestamporacle.sql.TIMESTAMPTZTIMESTAMP WITH LOCAL TIME ZONEoracle.jdbc.OracleTypes.TIMESTAMPLTZjava.sql.Timestamporacle.sql.TIMESTAMPLTZ

January 5, 2022 · 1 min · jiezi

关于mybatis:记一次未指定jdbcType导致的报错

报错现场还原一个批量入库的sql本人测试的时候失常,在线上报了 ### Error updating database. Cause: java.sql.SQLSyntaxErrorException: ORA-01790: 表达式必须具备与对应表达式雷同的数据类型 原来的sql是这样写的 <insert id="batchInsert"> insert into <include refid="TABLE_NAME"/> ( CID, TS, PHONE, NUM_PACKAGE, COST_MONTHPRICE, COST_PRICE, ONLINE_TIME, LOG_TIME ) <foreach collection="list" item="item" separator="union all"> select #{item.cid}, #{item.ts}, #{item.phone}, #{item.numPackage}, #{item.costMonthprice}, #{item.costPrice}, #{item.onlineTime}, sysdate from dual </foreach> </insert>其中onlineTime字段在现场有空的状况,狐疑未加jdbcType=DATE的状况下mybatis将这个字段置为了''空串。 <insert id="batchInsert"> insert into <include refid="TABLE_NAME"/> ( CID, TS, PHONE, NUM_PACKAGE, COST_MONTHPRICE, COST_PRICE, ONLINE_TIME, LOG_TIME ) <foreach collection="list" item="item" separator="union all"> select #{item.cid,jdbcType=INTEGER}, #{item.ts,jdbcType=INTEGER}, #{item.phone,jdbcType=VARCHAR}, #{item.numPackage,jdbcType=VARCHAR}, #{item.costMonthprice,jdbcType=VARCHAR}, #{item.costPrice,jdbcType=VARCHAR}, #{item.onlineTime,jdbcType=DATE}, sysdate from dual </foreach> </insert>我记得这个jdbcType有时还会引发索引生效的问题,所以当前还是都带上这个配置吧。 ...

January 5, 2022 · 1 min · jiezi

关于mybatis:mybatis之反射优化

本篇次要介绍一下 mybatis 的反射优化相干内容,让咱们理解一下 mybatis 的反射优化是怎么做的以及为什么须要做反射优化,基于3.4.6版本 知识点什么是反射mybatis为什么要优化mybatis是怎么优化的什么是反射说到反射,我置信大家有思考过持续走技术路线的必定都据说过。咱们平时在创立一个对象并调用对应办法的时候,都是通过以下形式来做的 A a = new A();a.do();然而如果咱们应用反射的形式,则是这样实现的 A a = A.class.newInstance();或者 Constructor<A> constructor = A.class.getDeclaredConstructor();if (!constructor.isAccessible()) { constructor.setAccessible(true); }A obj =constructor.newInstance();为什么这么麻烦,这么做有什么益处呢?反射最大的益处就是灵便。这里先解释一个概念,对于new形式创立的对象,是在编译期就确定的,而对于反射创立的对象,是在运行期创立的。灵便就体现在它是运行期(.class文件)确定创立的,试想一下,如果咱们有一个需要须要在 oracle 数据库和 mysql 数据库之间动静切换,那么咱们在创建对象实例的时候是不是依据传入的数据库类型来动态创建会比拟好,这样的话代码里只有写好加载对应类的逻辑,至于有没有这个类咱们齐全能够在内部来定(是否有.class文件),当然,如果是为了精简代码,也是一种十分好的抉择。举个例子,咱们来定义一个依据类型获取对象的办法 不必反射: public <T> T getInstance(Class<T> tClass){ if (tClass == A.class){ return (T)new A(); } if (tClass == B.class){ return (T)new B(); } throw new IllegalArgumentException("tClass unknow"); }应用反射: public <T> T getInstance(Class<T> tClass){ Assert.isTrue(tClass == ReflectionObject.class || tClass == UserInfo.class, "tClass unknow"); try{ return tClass.newInstance(); } catch (Exception ex){ //log throw new RuntimeException(ex); }mybatis为什么要优化在咱们理解了什么时候反射以及应用反射有什么益处之后,接着来看下反射有哪些问题。间接上代码,先定义一个对象 ...

January 4, 2022 · 3 min · jiezi

关于mybatis:mybatis之执行器

本篇来聊一下mybatis的执行器,看看如何在不同场景应用不同执行器以及不同执行器的实现原理是怎么的(基于mybatis 3.4.6)。 知识点什么是执行器mybatis执行器类型及何时应用各个执行器的实现原理 什么是执行器顾名思义,执行器就是用来执行咱们的 sql 语句,从而取到后果或对数据库进行更新的货色。它是 mybatis 中十分外围的概念,它提供了增、改、查、事务管理等基本操作接口,基本上所有的货色都是围绕执行器来进行,看下图 mybatis执行器类型及何时应用执行器类型咱们先来看下 mybatis 目前有哪些执行器类型 SIMPLEREUSEBATCH咱们能配置的目前就以上三种执行器,通过 defaultExecutorType(留神是全局的)来指定应用哪种,如果是通过 xml 形式配置的,则参照官网如果是应用spring boot集成的,则如下上面咱们别离对三种执行器来一一介绍。 SIMPLE能够了解为根本的执行器,这也是 mybatis 的默认执行器,也是咱们平时用的最多的执行器,咱们无需做任何配置更改。它大抵的流程是:关上连贯-> 设置 Statement -> 参数注入 -> 执行 -> 后果映射 -> 敞开 Statement ,能够看到每次用完之后会把 Statement 关掉。 REUSE看名字就晓得这是一个可重用执行器,什么叫可重用呢?指的是 simple 流程中的后面两步能够反复利用,也就是 关上连贯-> 设置 Statement,这两步会创立一个新的 Statement,reuse 执行器外部保护一个缓存,第一次获取后就会以对应的 sql (占位符 ? 不被具体参数替换)作为key进行缓存该 Statement,并且不对 Statement 进行敞开,前面遇到该 sql 只有从第三步开始做就能够了,这样就带来了性能上的优化(实际上优化并不大)。 BATCH同样通过名称就能看进去这是一个批量执行器,批量是什么意思?就是说它是能够一次性执行一批 sql 语句的,次要是针对更新、插入等批改性操作,对于单条或者查问类操作,就不要用这个执行器了,为什么能做到批量执行呢,其实实质上是用的 sql 包里的 PreparedStatement 的 addBatch(),前面原理局部再细说。 何时应用分明了三种执行器类型的特点之后,咱们再来比照下在不同场景下的性能输入,这样大家就分明何时应用何种类型执行器了,这里没有比照更新操作,是因为插入操作实质上用的就是更新操作接口。基于 spring 应用的 mybatis,基于以下表构造 单条查问先上代码 DefaultSqlSessionFactory sqlSessionFactory = (DefaultSqlSessionFactory)applicationContext.getBean("sqlSessionFactory"); //这里本人抉择执行器类型 DefaultSqlSession defaultSqlSession = (DefaultSqlSession)sqlSessionFactory.openSession(ExecutorType.SIMPLE); long startTime = System.currentTimeMillis();// userInfoMapper.selectById(22222); defaultSqlSession.selectList("com.example.mybatisanalyze.mapper.UserInfoMapper.selectById", 22222); long endTime = System.currentTimeMillis(); System.out.println((endTime - startTime) + "ms");simple:从图中能够看出花了42msreuse:将 DefaultSqlSession defaultSqlSession = (DefaultSqlSession)sqlSessionFactory.openSession(ExecutorType.SIMPLE); 改为 DefaultSqlSession defaultSqlSession = (DefaultSqlSession)sqlSessionFactory.openSession(ExecutorType.REUSE);从图中能够看出花了34msbatch:将 DefaultSqlSession defaultSqlSession = (DefaultSqlSession)sqlSessionFactory.openSession(ExecutorType.SIMPLE); 改为 DefaultSqlSession defaultSqlSession = (DefaultSqlSession)sqlSessionFactory.openSession(ExecutorType.BATCH);从图中能够看出花了43ms论断:单条查问三种执行器差不多,然而倡议抉择simple,起因见执行器类型中阐明。 ...

December 21, 2021 · 2 min · jiezi

关于mybatis:Mybatis源码Executor的执行过程

前言在Mybatis源码-SqlSession获取文章中曾经晓得,Mybatis中获取SqlSession时会创立执行器Executor并存放在SqlSession中,通过SqlSession能够获取映射接口的动静代理对象,动静代理对象的生成能够参考Mybatis源码-加载映射文件与动静代理,能够用下图进行概括。 所以,映射接口的动静代理对象理论执行办法时,执行的申请最终会由MapperMethod的execute()办法实现。本篇文章将以MapperMethod的execute()办法作为终点,对Mybatis中的一次理论执行申请进行阐明,并联合源码对执行器Executor的原理进行阐释。本篇文章不会对Mybatis中的缓存进行阐明,对于Mybatis中的一级缓存和二级缓存相干内容,会在后续的文章中独自进行剖析,为了屏蔽Mybatis中的二级缓存的烦扰,须要在Mybatis的配置文件中增加如下配置以禁用二级缓存。 <settings> <setting name="cacheEnabled" value="false"/></settings>注释本节将以一个理论的查问例子,以单步跟踪并联合源码的办法,对Mybatis的一次理论执行申请进行阐明。给定映射接口如下所示。 public interface BookMapper { Book selectBookById(int id);}给定映射文件如下所示。 <?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.mybatis.learn.dao.BookMapper"> <resultMap id="bookResultMap" type="com.mybatis.learn.entity.Book"> <result column="b_name" property="bookName"/> <result column="b_price" property="bookPrice"/> </resultMap> <select id="selectBookById" resultMap="bookResultMap"> SELECT b.id, b.b_name, b.b_price FROM book b WHERE b.id=#{id} </select></mapper>Mybatis的执行代码如下所示。 public class MybatisTest { public static void main(String[] args) throws Exception { String resource = "mybatis-config.xml"; SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .build(Resources.getResourceAsStream(resource)); //获取SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); //获取映射接口的动静代理对象 BookMapper bookMapper = sqlSession.getMapper(BookMapper.class); //执行一次查问操作 System.out.println(bookMapper.selectBookById(1)); }}基于上述的映射接口,映射文件和执行代码,最终执行查问操作时,会调用到MapperMethod的execute()办法并进入查问的逻辑分支,这部分源码如下所示。 ...

December 20, 2021 · 3 min · jiezi

关于mybatis:mybatis之事务管理

本篇来聊聊mybatis的事务管理机制,基于mybatis 3.4.6、mybatis-spring 1.3.2。 知识点什么是事务mybatis反对的事务管理形式mybatis事务管理实现机制spring是如何集成的什么是事务学过sql的必定都晓得这个概念,事务在sql中是十分重要的概念。这里做一个简略的介绍。 事务( Transaction)由一次或者屡次基本操作形成,或者说,事务由一条或者多条 SQL 语句形成,事务中的所有操作是一个整体,要么全副执行胜利,要么全副执行失败。它有4个根本的个性,别离是原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability),简称 ACID。 1) 原子性一个事务中的所有 SQL 语句,要么全副执行胜利,要么全副执行失败,不会完结在两头的某个环节。事务在执行过程中产生谬误,会被回滚(Rollback)到事务开始前的状态,就像这个事务素来没有执行过一样。 2) 一致性在事务开始之前和事务完结当前,数据库的完整性没有被毁坏。这示意写入的数据必须完全符合所有的预设规定,其中蕴含数据的精确度、串联性以及后续数据库能够自发性地实现预约的工作。 3) 隔离性数据库容许多个并发事务同时对其数据进行读写和批改的能力,隔离性能够避免多个事务并发执行时因为穿插执行而导致数据的不统一。事务隔离分为不同级别,包含读未提交(Read uncommitted)、读提交(read committed)、可反复读(repeatable read)和串行化(Serializable)。 4) 持久性事务处理完结后,对数据的批改就是永恒的,即使系统故障也不会失落。 mybatis反对的事务管理形式mybatis目前反对两种形式治理事务 原生jdbc容器托管先介绍一下原生jdbc,原生jdbc就是咱们间接在mybatis的配置文件中配置对应的数据库信息,对应的事务相干操作都由mybatis内置的JdbcTransaction来实现,相当于是不依赖于任何容器的,配置形式官网也提到了这里的 type 填 JDBC 就能够了,须要留神的是如果要用原生 jdbc 形式的,必须通过配置文件来实现,不反对 spring 的配置形式。再说一下容器托管形式。顾名思义就是将事务操作托管给具体的容器来实现。容器是什么意思?简略的了解,咱们能够认为就是相似于spring这种存在,联合起来就是mybatis将事务的治理实现交给spring来实现,它有一个益处就是能够和容器共用一个数据库连贯,不必两边来各自治理,spring对于mybatis的集成就是本人实现了一个专门的容器托管类来做的。 mybatis事务管理实现机制mybatis 的事务管理实现比较简单,都在这一块了这里用到了工厂模式来实现,对于原生的jdbc形式,通过JdbcTransaction来治理能够看到这里间接用了数据库连贯的提交和回滚操作。你可能认为托管的实现就是ManagedTransaction,其实并不是。那为什么有这个类,我猜测这里只是提供了样例般的代码,理论预计也是为了兼容mybatis的不同配置。能够看到它并没有做任何事件对于TransactionFactory,它是依附于Environment中的,mybatis 都是通过Environment来获取对应的TransactionFactory,而后再创立相应的Transaction。这也是为什么咱们能够配置不同环境来配置不同数据库信息来做到环境隔离。而对于Transaction,它是依附于Executor的,也就是执行器,这个设计也非常容易了解,因为执行器自身就是对数据库做增删改查操作的,事务也放到外面一起治理十分正当。 spring是如何集成的通过下面的内容,咱们晓得 mybatis 反对事务管理托管给容器解决,而 spring 就是这种形式十分经典实现。因为咱们目前用的大多是 spring 框架,所以咱们在我的项目中用 mybatis 的时候都会引入mybatis-spring这个 jar 包,这个包就是 spring 集成 mybatis 的关键所在,外面波及内容也有不少,但这里只剖析事务管理这一块。对于mybatis的集成,这里有个很要害的类SqlSessionFactoryBean能够看到这是一个FactoryBean,就是通过它来获取SqlSessionFactory的,间接看外围逻辑org.mybatis.spring.SqlSessionFactoryBean#buildSqlSessionFactory能够看到这里创立了spring实现的事务管理类SpringManagedTransactionFactory,而后创立了一个Environment设置到Configuration中,这样后续 mybatis 在获取事务的时候获取到的都是SpringManagedTransactionFactory。所有实现都在这个包上面,构造是不是很相熟,就是基于 mybatis 的工厂模式那一套。 总结mybatis的事务管理实现还是绝对比较简单的,其实咱们平时本人去配置具体的事务管理类也很少,因为如果用的spring,根本不必再本人做什么解决了,然而这个设计还是不错的,间接把相干模块交给容器解决,容器接入也简略。

December 13, 2021 · 1 min · jiezi

关于mybatis:Mybatis源码动态SQL的实现原理

前言Mybatis提供了弱小的动静SQL语句生成性能,以应答简单的业务场景,本篇文章将联合Mybatis解析SQL语句的过程对Mybatis中对<if>,<where>,<foreach>等动静SQL标签的反对进行剖析。 注释一. XML文档中的节点概念在剖析Mybatis如何反对SQL语句之前,本大节先剖析XML文档中的节点概念。XML文档中的每个成分都是一个节点,DOM对XML节点的规定如下所示。 整个文档是一个文档节点;每个XML标签是一个元素节点;蕴含在元素节点中的文本是文本节点。以一个XML文档进行阐明,如下所示。 <provinces> <province name="四川"> <capital>成都</capital> </province> <province name="湖北"> <capital>武汉</capital> </province></provinces>如上所示,整个XML文档是一个文档节点,这个文档节点有一个子节点,就是<provinces>元素节点,<provinces>元素节点有五个子节点,别离是:文本节点,<province>元素节点,文本节点,<province>元素节点和文本节点,留神,在<provinces>元素节点的子节点中的文本节点的文本值均是\n,示意换行符。同样,<province>元素节点有三个子节点,别离是:文本节点,<capital>元素节点和文本节点,这里的文本节点的文本值也是\n,而后<capital>元素节点只有一个子节点,为一个文本节点。节点的子节点之间互为兄弟节点,例如<provinces>元素的五个子节点之间互为兄弟节点,name为“四川”的<province>元素节点的上一个兄弟节点为文本节点,下一个兄弟节点也为文本节点。 二. Mybatis反对动静SQL源码剖析在Mybatis源码-加载映射文件与动静代理中曾经晓得,在XMLStatementBuilder的parseStatementNode()办法中,会解析映射文件中的<select>,<insert>,<update>和<delete>标签(后续对立称为CURD标签),并生成MappedStatement而后缓存到Configuration中。CURD标签的解析由XMLLanguageDriver实现,每个标签解析之后会生成一个SqlSource,能够了解为SQL语句,本大节将对XMLLanguageDriver如何实现CURD标签的解析进行探讨。 XMLLanguageDriver创立SqlSource的createSqlSource()办法如下所示。 public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) { XMLScriptBuilder builder = new XMLScriptBuilder( configuration, script, parameterType); return builder.parseScriptNode();}如上所示,createSqlSource()办法的入参中,XNode就是CURD标签对应的节点,在createSqlSource()办法中先是创立了一个XMLScriptBuilder,而后通过XMLScriptBuilder来生成SqlSource。先看一下XMLScriptBuilder的构造方法,如下所示。 public XMLScriptBuilder(Configuration configuration, XNode context, Class<?> parameterType) { super(configuration); this.context = context; this.parameterType = parameterType; initNodeHandlerMap();}在XMLScriptBuilder的构造方法中,次要是将CURD标签对应的节点缓存起来,而后初始化nodeHandlerMap,nodeHandlerMap中寄存着解决Mybatis提供的反对动静SQL的标签的处理器,initNodeHandlerMap()办法如下所示。 private void initNodeHandlerMap() { nodeHandlerMap.put("trim", new TrimHandler()); nodeHandlerMap.put("where", new WhereHandler()); nodeHandlerMap.put("set", new SetHandler()); nodeHandlerMap.put("foreach", new ForEachHandler()); nodeHandlerMap.put("if", new IfHandler()); nodeHandlerMap.put("choose", new ChooseHandler()); nodeHandlerMap.put("when", new IfHandler()); nodeHandlerMap.put("otherwise", new OtherwiseHandler()); nodeHandlerMap.put("bind", new BindHandler());}当初剖析XMLScriptBuilder的parseScriptNode()办法,该办法会创立SqlSource,如下所示。 ...

December 9, 2021 · 3 min · jiezi

关于mybatis:mybatis之类型处理器

本篇次要介绍一下 mybatis 的类型处理器,基于3.4.6版本。 知识点什么是类型处理器类型处理器的作用如何自定义类型处理器实现原理什么是类型处理器咱们平时在应用 mybatis 的时候比较简单,只有写一个 sql 语句,而后定义好对应的接口就能够应用了,这里就波及到一个问题:咱们调用接口的时候传入的明明是 java 的数据类型,为什么可能失常存到数据库里呢,咱们从数据库里取出来的明明是数据库中的类型,为什么可能间接在代码里拿到 java 类型呢?类型处理器就是来解决这个问题的,用 mybatis 的术语,就是 TypeHandler。 类型处理器的作用其实下面也说到了,类型处理器的作用非常简单,总结起来就2种 将咱们传入接口的参数转换为对应的数据库类型将数据库种查问回来的字段类型转换为对应的java类型如何自定义类型处理器咱们晓得 mybatis 内置了很多类型的处理器,这也是咱们什么都不做,间接可能实现类型转换的起因,看下目前有哪些类型处理器能够看到,type目录下简直全是,有趣味的能够本人去看下,这里不多做介绍。如果遇到了内置处理器无奈解决的新类型,或者咱们想要在内置的类型处理器上加一些本人的逻辑,怎么办呢?这时就须要自定义类型处理器了。这个比较简单,其实官网文档里也介绍过了,这里再具体介绍一下1) 继承 BaseTypeHandler ,我这里解决的是String 类型 public class MyTypeHandler extends BaseTypeHandler<String> { @Override public void setNonNullParameter(PreparedStatement preparedStatement, int i, String s, JdbcType jdbcType) throws SQLException { preparedStatement.setString(i, s); } @Override public String getNullableResult(ResultSet resultSet, String s) throws SQLException { return null; } @Override public String getNullableResult(ResultSet resultSet, int i) throws SQLException { return null; } @Override public String getNullableResult(CallableStatement callableStatement, int i) throws SQLException { return null; }}2)最简略的状况下下面定义曾经能够了,咱们还能够本人指定处理器解决的数据库字段类型,通过@MappedJdbcTypes注解来指定,比方我这里要解决的是表中的 varchar 类型数据,如果不指定则默认取 key 为 null 的对应jdbc类型处理器 ...

December 8, 2021 · 1 min · jiezi

关于mybatis:MyBatis动态sql实现技巧如何判断Boolean类型

当查问条件有Boolean类型的时候,为false时查问有效<if test="isOk != null and isOk !=''"> and is_ok = #{isOk}</if>当isOk = false 时,并未查问出is_ok对应的后果来-- sql: 没有拼接where = isOk的条件select * from tableName;当 isOk = true 时,查问后果正确-- sqlselect * from tableName where is_ok = true ;问题所在:<if test="isOk != null and isOk !=''"> 正确写法Boolean类型默认值为null,只须要判断是否为null<if test="isOk != null"> and is_ok = #{isOk}</if>isOk = '' , 会将 '' 转换成null解决

October 28, 2021 · 1 min · jiezi

关于mybatis:mybatis解读

1.sqlSession和connection的区别艰深了解:一个sqlSession对应一个connection,sqlSession是用来操作connection的 Connection作为一个特定数据库的会话,在一个连贯的上下文中,sql语句被执行,而后后果被返回。咱们在一次Connection上下文中能够执行多个操作。然而默认状况下,一个connection被创立时,默认是auto-commit模式,statement执行完sql后主动commit。这样,尽管多个操作在同一个Connection上下文中执行,他们本人只和本人有关系,然而他们之间没有什么关系。如果咱们想多个操作,同时胜利或同时失败,那就要设置禁止auto-commit模式,而后手动commit 。这样一次Connection中的几个操作,就具备同时胜利或者同时失败的关系。 1.注册驱动Class.forName("com.mysql.jdbc.Driver");2.获取数据库连贯Connection conn =DriverManager.getConnection(url,user,p);3.创立向数据发送sql 的statement对象Statement stmt = conn.CreateStatement();4.向数据库发送sqlResultSet rs = stmt.executeQuery(sql)//select语句int updateaSum = stmt.executeUpdate(sql)//insert,update delete语句5. 处理结果集while(rs.next()){ rs.getString(列名) rs.getInt(列名)}6. 敞开资源rs.close();stmt.close();conn.close();SqlSession能够看作是对Connection 更加高级的形象,从其办法上更加能够看出他具备更加显著的操作特色。 void select(String statement, ResultHandler handler); int insert(String statement, Object parameter); int update(String statement); int delete(String statement, Object parameter)2.sqlSession的原理一个sqlsession个别对应一个connection,并且mybatis默认每次获取session都会开启一个事务,且不主动提交事务。如果更新操作实现后不手动commit,则在连贯断开时会将更新操作回滚,一个sqlSession(一个transaction)中能够屡次commit,commit后cache和statement刷新(个别一个事务(transaction)只对应一个sqlseesion,也即一个connection,分布式一个事务能够对应多个connection),只有close后同时敞开sqlsession和transaction(transaction能够由factory敞开)并返回connection。mybatis的transaction根本没增加什么性能,大部分仅状态判断后交由connection(再由jdbc)执行。可能是为了给spring等框架容易组转本人的事务管理机制 思考2.1为什么每次都要执行sql完结都会登程sqlSession.close()?同一个线程应用ThreadLocal中只保留一份不好吗?Connection对象是线程不平安的,为防止多个线程才做同一个connection对象,能够采纳ThreadLocal机制。sqlSession是对connection的进一步封装。事务存在的状况下,sqlSession会存在复用以确保事务的失常运行和回滚。事务不存在的状况下,sqlSession对象是能够始终应用ThreadLocal中与该线程绑定的同一个connection,然而此种形式并不优雅,mybatis也并没有采纳。理由如下:connection对象能够被看为一种可复用的资源,应用连接池技术更加正当,否则,同一个sqlSession始终持有同一个connection不开释,在不进行DB操作时也占用着该链接,将会很消耗资源,而mybatis是采纳链接池记述,看似“create”,实为复用同一个链接对象。看似“close”,实为开释回链接池,很好的解决啦资源节约,又保障了设计准则 2.2 事务是怎么实现的?事务的流传行为又是怎么的 事务是通过sqlSessionHolder等类实现的,事务实现的根底是事务中的所有长久化操作应用的是同一个connection。故多线程状况下不存在事务的流传行为 参考文献:https://blog.csdn.net/hcy5421... https://cloud.tencent.com/dev...

October 25, 2021 · 1 min · jiezi

关于mybatis:mybatis学习记录-二-映射文件

1. 参数解决在上个博客中,咱们能够看到UserMapper.java和UserMapper.xml文件中有这相应的对应,在这里我先将这两个文件的代码展现进去。 1.1 文件展现UserMapper.java package com.jt;import org.apache.ibatis.annotations.Param;import org.apache.ibatis.annotations.Select;import java.util.Map;public interface UserMapper { public User selectUser(int id);//单个参数传递 public User selectUserByIdAndName(@Param("id") Integer id,@Param("username") String username);// 多个参数传递 public User selectUserByIdAndNameUseMap(Map map);//多个参数传递 public Integer insertUser(User user); public boolean updateUser(User user); public Integer deleteUserById(int id);}UserMapper.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="com.jt.UserMapper"> <select id="selectUser" resultType="com.jt.User"> select * from test01 where id = #{id} </select> <select id="selectUserByIdAndName" resultType="com.jt.User"> select * from test01 where id = #{id} and username=#{username} </select> <select id="selectUserByIdAndNameUseMap" resultType="com.jt.User"> select * from test01 where id = #{id} and username=#{username} </select> <insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> insert into test01 (username,password) values(#{username},#{password}) </insert> <update id="updateUser" parameterType="com.jt.User"> update test01 set username=#{username} where id=#{id} </update> <delete id="deleteUserById"> delete from test01 where id=#{id} </delete></mapper>1.2 文件剖析在UserMapper.java接口文件中,传递的参数有,单个参数,多个参数的状况。 ...

October 11, 2021 · 2 min · jiezi

关于mybatis:mybatis-学习记录-一

一、 Mybatis HelloWorld1. 应用Maven创立一个我的项目,我的项目目录如下 2. 在maven 的pom.xml引入依赖次要包含mybatis,mysql,junit的依赖,而后就可进行开发了。 <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>test03</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.22</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> </dependencies></project>3. 编写mybatis配置文件 mybatis-config.xml文件次要是用来配置数据源 和 配置相干mapper*.xml文件 <?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.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <mapper resource="UserMapper.xml"/> </mappers></configuration>4.创立用户表,编写User类 package com.jt;public class User { private int id; private String username; private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; }}5.编写UserMapper类package com.jt;import org.apache.ibatis.annotations.Param;import org.apache.ibatis.annotations.Select;import java.util.Map;public interface UserMapper { public User selectUser(int id); public User selectUserByIdAndName(@Param("id") Integer id,@Param("username") String username); public User selectUserByIdAndNameUseMap(Map map); public Integer insertUser(User user); public boolean updateUser(User user); public Integer deleteUserById(int id);}6.编写UserMapper.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="com.jt.UserMapper"> <select id="selectUser" resultType="com.jt.User"> select * from test01 where id = #{id} </select> <select id="selectUserByIdAndName" resultType="com.jt.User"> select * from test01 where id = #{id} and username=#{username} </select> <select id="selectUserByIdAndNameUseMap" resultType="com.jt.User"> select * from test01 where id = #{id} and username=#{username} </select> <insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> insert into test01 (username,password) values(#{username},#{password}) </insert> <update id="updateUser" parameterType="com.jt.User"> update test01 set username=#{username} where id=#{id} </update> <delete id="deleteUserById"> delete from test01 where id=#{id} </delete></mapper>7.编写测试类import com.jt.User;import com.jt.UserMapper;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 org.junit.Test;import java.io.IOException;import java.io.InputStream;import java.util.LinkedHashMap;import java.util.Map;public class HelloTest { @Test public void selectTest() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); try (SqlSession session = sqlSessionFactory.openSession()) { UserMapper userMapper = session.getMapper(UserMapper.class); User user = userMapper.selectUser(1); System.out.println(user); }finally { sqlSessionFactory.openSession(); } } @Test public void selectByIdAndNameTest() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); try (SqlSession session = sqlSessionFactory.openSession()) { UserMapper userMapper = session.getMapper(UserMapper.class); User user = userMapper.selectUserByIdAndName(5,"3"); System.out.println(user); }finally { sqlSessionFactory.openSession(); } } @Test public void selectByIdAndNameUseMapTest() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); try (SqlSession session = sqlSessionFactory.openSession()) { UserMapper userMapper = session.getMapper(UserMapper.class); Map map = new LinkedHashMap(); map.put("id",5); map.put("username","3"); User user = userMapper.selectUserByIdAndNameUseMap(map); System.out.println(user); }finally { sqlSessionFactory.openSession(); } } @Test public void insertTest() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); try (SqlSession session = sqlSessionFactory.openSession()) { UserMapper userMapper = session.getMapper(UserMapper.class); User user01 = new User(); user01.setUsername("4"); user01.setPassword("4"); userMapper.insertUser(user01); System.out.println(user01.getId()); }finally { sqlSessionFactory.openSession(); } } @Test public void updateTest() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); try (SqlSession session = sqlSessionFactory.openSession()) { UserMapper userMapper = session.getMapper(UserMapper.class); User user01 = new User(); user01.setId(2); user01.setUsername("批改1"); boolean res = userMapper.updateUser(user01); System.out.println(res); }finally { sqlSessionFactory.openSession(); } } @Test public void deleteTest() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); try (SqlSession session = sqlSessionFactory.openSession()) { UserMapper userMapper = session.getMapper(UserMapper.class); int res = userMapper.deleteUserById(1); System.out.println(res); }finally { sqlSessionFactory.openSession(); } }}

October 11, 2021 · 3 min · jiezi

关于mybatis:Mybatis-Generator-Plugin悲观锁实现

前言Mybatis Generator插件能够疾速的实现根底的数据库CRUD操作,它同时反对JAVA语言和Kotlin语言,将程序员从反复的Mapper和Dao层代码编写中释放出来。Mybatis Generator能够主动生成大部分的SQL代码,如update,updateSelectively,insert,insertSelectively,select语句等。然而,当程序中须要SQL不在主动生成的SQL范畴内时,就须要应用自定义Mapper来实现,即手动编写DAO层和Mapper文件(这里有一个小坑,当数据库实体减少字段时,对应的自定义Mapper也要及时手动更新)。抛开简单的定制化SQL如join,group by等,其实还是有一些比拟罕用的SQL在根底的Mybatis Generator工具中没有主动生成,比方分页能力,乐观锁,乐观锁等,而Mybatis Generator也为这些诉求提供了Plugin的能力。通过自定义实现Plugin能够扭转Mybatis Generator在生成Mapper和Dao文件时的行为。本文将从乐观锁为例,让你疾速理解如何实现Mybatis Generator Plugin。 实现背景:数据库:MYSQLmybatis generator runtime:MyBatis3 <!-- more --> 实现Mybatis乐观锁当业务呈现须要保障强统一的场景时,能够通过在事务中对数据行上乐观锁后再进行操作来实现,这就是经典的”一锁二判三更新“。在交易或是领取零碎中,这种诉求十分广泛。Mysql提供了Select...For Update语句来实现对数据行上乐观锁。本文将不对Select...For Update进行具体的介绍,有趣味的同学能够查看其它文章深刻理解。 Mybatis Generator Plugin为这种具备通用性的SQL提供了很好的反对。通过继承org.mybatis.generator.api.PluginAdapter类即可自定义SQL生成逻辑并在在配置文件中应用。PluginAdapter是Plugin接口的实现类,提供了Plugin的默认实现,本文将介绍其中比拟重要的几个办法: public interface Plugin { /** * 将Mybatis Generator配置文件中的上下文信息传递到Plugin实现类中 * 这些信息包含数据库链接,类型映射配置等 */ void setContext(Context context); /** * 配置文件中的所有properties标签 **/ void setProperties(Properties properties); /** * 校验该Plugin是否执行,如果返回false,则该插件不会执行 **/ boolean validate(List<String> warnings); /** * 当DAO文件实现生成后会触发该办法,能够通过实现该办法在DAO文件中新增办法或属性 **/ boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable); /** * 当SQL XML 文件生成后会调用该办法,能够通过实现该办法在MAPPER XML文件中新增XML定义 **/ boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable);}这里联合Mybatis Generator的配置文件和生成的DAO(也称为Client文件)和Mapper XML文件能够更好的了解。Mybatis Generator配置文件样例如下,其中蕴含了次要的一些配置信息,如用于形容数据库链接的<jdbcConnection>标签,用于定义数据库和Java类型转换的<javaTypeResolver>标签等。 ...

September 27, 2021 · 4 min · jiezi

关于mybatis:SpringBoot系列Mybatis之转义符的使用姿势

【DB 系列】Mybatis 之本义符的应用姿态在 mybatis 的 xml 文件中间接写 sql 比拟不便简洁,然而须要留神的是,在 xml 文件中,常常会遇到一些须要本义的场景,比方查问 id < xxx的数据,这个小于号就不能间接写在 sql 中,接下来咱们将看一下,mybatis 中的有哪些本义符,能够怎么解决本义问题 <!-- more --> I.本义1. 本义符在 mybatis 的 xml 文件中,咱们最常见的本义符为小于号,如查问 id 小于 100 的数据 <select id="xxx"> select * from `money` where id &lt; #{id}</select>留神下面的 sql,小于号理论应用的是 &lt;,不能间接应用 <,比方间接应用小于号,在 idea 中会有如下的谬误提醒 日常开发中除了下面的小于号之外,另外一个常见的则是 & 与操作符,如果 sql 中有位操作的场景,同样须要本义 <select id="xxx"> -- select * from `money` where id & 1 = 1 的sql,须要如下本义 select * from `money` where id &amp; 1 = 1</select>在 mybatis 中常见的几个转义字符表映射关系如下表 (mybatis 的本义实际上齐全遵循的是 xml 本义规定,次要有上面几个) ...

September 27, 2021 · 1 min · jiezi

关于mybatis:Mybatis新手进阶知识点老鸟请走开

ORM全称:object relation mapping,译为:对象关系映射。ORM框架是将对象和数据库表字段建设映射,并提供CRUD操作的API的框架。Java原生的与数据库连贯的形式是JDBC,每次操作须要以下6个步骤 加载数据库驱动创立连贯创立一个Statement执行SQL处理结果集敞开连贯原生的形式步骤繁琐,开发效率低,市面上有很多的优良的ORM框架: Hibernate 全自动ORM框架,弱化sql, 甚至不须要思考建表,Hibernate会依据对象生成表甚至两头表。CURD个别不须要写sql。用起来不便,用好很难,有些老的我的项目还在用。Mybatis半自动ORM框架,本文的配角,被宽泛应用,它反对自定义 SQL、存储过程以及高级映射。前身是ibatis, 另外还有一个在此基础上封装的号称为简化开发而生的框架MyBatis-Plus。提供通用的CURD,个别操作不须要写sql。JPA是大spring旗下ORM框架,特点是依据办法名就能主动实现办法逻辑,你敢信?不信能够看看这篇文章《简略才是美! SpringBoot+JPA》上面将介绍一些mybatis老手进阶知识点,老鸟请走开♂️ 嵌套查问在resultMap中嵌套一个查问。通过标签<association>的select属性实现。select的值是另一个<select>查问的id,column属性为关联字段,用来实现关联查问。依据user_id查问user <select id="getUserWithAddress2" resultMap="BaseResultWithAddress2Map"> select * from `user` where user_id = #{userId} </select><association>中嵌套一个id为selectAddressByUserId的查问,查问这个用户的地址。 <resultMap id="BaseResultWithAddress2Map" type="com.mashu.springmybatis.entity.UserWithAddress"> <id column="user_id" property="userId" jdbcType="INTEGER"/> <result column="name" property="name" jdbcType="VARCHAR"/> <result column="email" property="email" jdbcType="VARCHAR"/> <association property="address" column="user_id" javaType="com.mashu.springmybatis.entity.Address" select="selectAddressByUserId"> </association> </resultMap>id为selectAddressByUserId的查问:依据用户id查问地址详情: <select id="selectAddressByUserId" resultMap="com.mashu.springmybatis.mapper.AddressMapper.BaseResultMap"> select * from address where user_id = #{userId} </select>嵌套后果下面的查问会有N+1的问题,就是执行两遍查问,能够应用联表查问解决这个问题,后果集同样是应用<resultMap>映射,<association>标签+resultMap属性。具体写法如下:association标签的resultMap属性指向address的resultMap <resultMap id="BaseResultWithAddressMap" type="com.mashu.springmybatis.entity.UserWithAddress"> <id column="user_id" property="userId" jdbcType="INTEGER"/> <result column="name" property="name" jdbcType="VARCHAR"/> <result column="email" property="email" jdbcType="VARCHAR"/> <association property="address" javaType="com.mashu.springmybatis.entity.Address" resultMap="com.mashu.springmybatis.mapper.AddressMapper.BaseResultMap"> </association></resultMap>联表查问sql <select id="getUserWithAddress" resultMap="BaseResultWithAddressMap"> select * from `user` u join address a on u.user_id and a.user_id where u.user_id = #{userId} </select>还能够一对多的映射,将<association>换成<collection>,实现一个人有多个女朋友的一对多关联查问。myabtis会主动合并反复的user,girlFriends作为汇合映射到user的girlFriends属性。 <resultMap id="BaseResultWithGirlFriendsMap" type="com.mashu.springmybatis.entity.UserWithGirlFriends"> <id column="user_id" property="userId" jdbcType="INTEGER"/> <result column="name" property="name" jdbcType="VARCHAR"/> <result column="email" property="email" jdbcType="VARCHAR"/> <collection property="girlFriends" ofType="com.mashu.springmybatis.entity.GirlFriend"> <id column="girl_friend_id" property="girlFriendId" jdbcType="INTEGER"/> <result column="user_id" property="userId" jdbcType="VARCHAR"/> <result column="girl_friend_name" property="name" jdbcType="VARCHAR"/> <result column="age" property="age" jdbcType="INTEGER"/> <result column="weight" property="weight" jdbcType="INTEGER"/> <result column="height" property="height" jdbcType="INTEGER"/> </collection> </resultMap>懒加载除了联表查问解决N+1的问题,mybatis的懒加载仿佛更好,拿第一个嵌套查问的栗子来说,如果开启了懒加载,在不应用address的时候,只会执行查问user的sql,不会执行查问address的sql。只有在应用中get了address属性才会执行查问address的sql,应用起来也很见简略: ...

September 8, 2021 · 2 min · jiezi

关于mybatis:从源码角度分析-MyBatis-工作原理

一、MyBatis 残缺示例这里,我将以一个入门级的示例来演示 MyBatis 是如何工作的。 注:本文前面章节中的原理、源码局部也将基于这个示例来进行解说。残缺示例源码地址 1.1. 数据库筹备在本示例中,须要针对一张用户表进行 CRUD 操作。其数据模型如下: CREATE TABLE IF NOT EXISTS user ( id BIGINT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Id', name VARCHAR(10) NOT NULL DEFAULT '' COMMENT '用户名', age INT(3) NOT NULL DEFAULT 0 COMMENT '年龄', address VARCHAR(32) NOT NULL DEFAULT '' COMMENT '地址', email VARCHAR(32) NOT NULL DEFAULT '' COMMENT '邮件', PRIMARY KEY (id)) COMMENT = '用户表';INSERT INTO user (name, age, address, email)VALUES ('张三', 18, '北京', 'xxx@163.com');INSERT INTO user (name, age, address, email)VALUES ('李四', 19, '上海', 'xxx@163.com');1.2. 增加 MyBatis如果应用 Maven 来构建我的项目,则需将上面的依赖代码置于 pom.xml 文件中: ...

September 7, 2021 · 10 min · jiezi

关于mybatis:mybatis基础之二Mybatis-SQL映射文件详解

在之前咱们学习了mybatis的全局配置文件,上面咱们开始学习mybatis的映射文件,在映射文件中,能够编写以下的顶级元素标签: cache – 该命名空间的缓存配置。cache-ref – 援用其它命名空间的缓存配置。resultMap – 形容如何从数据库后果集中加载对象,是最简单也是最弱小的元素。parameterMap – 老式格调的参数映射。此元素已被废除,并可能在未来被移除!请应用行内参数映射。文档中不会介绍此元素。sql – 可被其它语句援用的可重用语句块。insert – 映射插入语句。update – 映射更新语句。delete – 映射删除语句。select – 映射查问语句。 在每个顶级元素标签中能够增加很多个属性,上面咱们开始具体理解下具体的配置。 1、insert、update、delete元素属性形容id在命名空间中惟一的标识符,能够被用来援用这条语句。parameterType将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 能够通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。parameterMap用于援用内部 parameterMap 的属性,目前已被废除。请应用行内参数映射和 parameterType 属性。flushCache将其设置为 true 后,只有语句被调用,都会导致本地缓存和二级缓存被清空,默认值:(对 insert、update 和 delete 语句)true。timeout这个设置是在抛出异样之前,驱动程序期待数据库返回申请后果的秒数。默认值为未设置(unset)(依赖数据库驱动)。statementType可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 别离应用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。useGeneratedKeys(仅实用于 insert 和 update)这会令 MyBatis 应用 JDBC 的 getGeneratedKeys 办法来取出由数据库外部生成的主键(比方:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的主动递增字段),默认值:false。keyProperty(仅实用于 insert 和 update)指定可能惟一辨认对象的属性,MyBatis 会应用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,能够用逗号分隔多个属性名称。keyColumn(仅实用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,能够用逗号分隔多个属性名称。databaseId如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配以后 databaseId 的语句;如果带和不带的语句都有,则不带的会被疏忽。 <!--如果数据库反对自增能够应用这样的形式--> <insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> insert into user(user_name) values(#{userName}) </insert> <!--如果数据库不反对自增的话,那么能够应用如下的形式进行赋值查问--> <insert id="insertUser2" > <selectKey order="BEFORE" keyProperty="id" resultType="integer"> select max(id)+1 from user </selectKey> insert into user(id,user_name) values(#{id},#{userName}) </insert>2、select元素1、select的参数传递<!-- 当查问语句中蕴含多个参数的是,如果应用#{属性名称}就无奈获取具体的值了,那么应该如何应用呢? 上面就是mybatis的参数传递形式 1、如果是单个参数, 根本类型:应用#{轻易写} 援用类型:应用#{类的属性名称} 2、多个参数: 当查问的时候传入多个参数的时候,就无奈简略的通过#{参数名}来获取值了, 只能通过arg0,arg1...或者param1,param2等形式来获取值 起因就在于,mybatis在传入多个参数的时候,会将这些参数封装到一个map中,此时map中的key就是 arg0,arg1,param1,param2这些值,然而很显著,这样的传值形式不是很敌对,没有方法依据参数的名称来 获取具体的值,因而能够应用如下的形式来指定参数的key是什么 Emp selectEmpByNoAndName(@Param("empno") Integer empno, @Param("ename") String ename); 也就是通过@Param来指定存入map中的key值是什么 3、应用map来传递参数: 仍然是间接应用#{key}来获取具体的属性值 --> <select id="selectEmpByNoAndName" resultType="com.mashibing.bean.Emp"> select * from emp where empno=#{empno} and ename=#{ename} </select> <select id="selectEmpByNoAndName2" resultType="com.mashibing.bean.Emp"> select * from emp where empno=#{empno} and ename=#{ename} </select>2、参数的取值形式 在xml文件中编写sql语句的时候有两种取值的形式,别离是#{}和${},上面来看一下他们之间的区别: ...

August 22, 2021 · 12 min · jiezi

关于mybatis:Mybatis分页查询

思考:为什么要分页? 缩小数据的处理量1、应用Limit分页语法: select * from user limit startIndex,pageSize;select * from user limit 3;#[0,n]应用Mybatis实现分页,外围SQL接口 /** * 分页查问 * @return */ List<User> getUserByLimt(Map<String,Integer> map);Mapper.xml <!--分页实现查问 --><select id="getUserByLimt" parameterType="map" resultMap="UserMap"> select * from mybatis.user limit #{startIndex},#{pageSize}</select> //测试 public void getUserByLimt(){ SqlSession sqlsession = MybatisUtil.getSqlsession(); UserMapper mapper = sqlsession.getMapper(UserMapper.class); HashMap<String, Integer> map = new HashMap<String, Integer>(); map.put("startIndex",0); map.put("pageSize",3); List<User> userByLimt = mapper.getUserByLimt(map); for (User user : userByLimt) { System.out.println(user); } }2、RowBounds分页不在应用SQL实现分页 接口 /** * * @return */ List<User> getUserByRowBounds();Mapper.xml<!--分页实现查问 --> ...

August 13, 2021 · 1 min · jiezi

关于mybatis:Mybatis深入理解

1、外围配置文件 mybatis-config.xmlMyBatis 的配置文件蕴含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层构造如下:configuration(配置)perties(属性)settings(设置)typeAliases(类型别名)typeHandlers(类型处理器)objectFactory(对象工厂)plugins(插件)environments(环境配置)environment(环境变量)dataSource(数据源)transactionManager(事务管理器)databaseIdProvider(数据库厂商标识)mappers(映射器)2、环境配置mybatis能够配置成适应多种环境不过要记住:只管能够配置多个环境,然而每个SqlSessionFactory实例只能抉择一种环境Mybatis默认的事务管理器就是JDBC,连接池:POOLED3、属性(properties)咱们能够通过properties属性来实现援用配置文件这些属性能够在内部进行配置,并能够进行动静替换。你既能够在典型的 Java 属性文件中配置这些属性,也能够在 properties 元素的子元素中设置。【db.roperties】编写配置文件:db.propeties driver=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;charsetEncoding=UTF-8username=rootpassword=root在外围配置文件中引入 <properties resource="db.properties"> <property name="username" value="root"/> <property name="password" value="root"/> </properties>能够间接引入内部配置文件能够在其中减少以下属性配置如果两个文件有同一个字段,优先应用内部配置文件的!4、类型别名(typeAliases)类型别名可为 Java 类型设置一个缩写名字,它仅用于 XML 配置,意在升高冗余的全限定类名书写 <!--类型命名 能够给实体类起别名--> <!--<typeAliases></typeAliases>--> <typeAliases> <typeAlias type="com.aostarit.entity.User" alias="User"/> </typeAliases>也能够指定一个包名,Mybatis会在包名上面搜寻须要的Java Bean,比方:扫描实体类的包, 它的默认别名就是这个类的类名,首字母小写(大写能够,倡议小写)! <typeAliases> <!-- <typeAlias type="com.aostarit.entity.User" alias="User"/>--> <package name="com.aostarit.entity"/> </typeAliases>在实体类比拟少的时候,应用第一种形式,否则倡议应用第二种 如果实体类有注解,则别名为其注解值 @Alias("User")public class User {}5、设置(settings)6、其它配置 typeHandlers(类型处理器)objectFactory(对象工厂)plugins(插件)mybatis-generator-coremybatis-plus通用mapper7隐射器(mappers)MapperRegistry:注册绑定咱们的Mapper文件:形式一(举荐应用): <!--映射器--><mappers> <mapper resource="mapper/UserMapper.xml"/></mappers>应用二:应用class文件绑定注册 <mappers> <!-- <mapper resource="mapper/UserMapper.xml"/>--> <mapper class="com.aostarit.dao.UserMapper"/></mappers>留神点:接口和它的mapper配置文件必须同名接口和它的mapper配置文件必须在同一个包下形式三:应用扫描包进行注入绑定 <mappers> <!-- <mapper resource="mapper/UserMapper.xml"/>--> <!-- <mapper class="com.aostarit.dao.UserMapper"/>--> <package name="com.aostarit.dao"/></mappers>留神点:接口和它的mapper配置文件必须同名接口和它的mapper配置文件必须在同一个包下将数据库配置文件内部引入实体类别名保障UserMapper接口和UserMapper.xml改为统一!并且放在同一个包下

August 13, 2021 · 1 min · jiezi

关于mybatis:Mybatis配置解析

1、外围配置文件 mybatis-config.xmlMyBatis 的配置文件蕴含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层构造如下:configuration(配置)perties(属性)settings(设置)typeAliases(类型别名)typeHandlers(类型处理器)objectFactory(对象工厂)plugins(插件)environments(环境配置)environment(环境变量)dataSource(数据源)transactionManager(事务管理器)databaseIdProvider(数据库厂商标识)mappers(映射器)2、环境配置mybatis能够配置成适应多种环境不过要记住:只管能够配置多个环境,然而每个SqlSessionFactory实例只能抉择一种环境Mybatis默认的事务管理器就是JDBC,连接池:POOLED3、属性(properties)咱们能够通过properties属性来实现援用配置文件这些属性能够在内部进行配置,并能够进行动静替换。你既能够在典型的 Java 属性文件中配置这些属性,也能够在 properties 元素的子元素中设置。【db.roperties】编写配置文件:db.propeties driver=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;charsetEncoding=UTF-8username=rootpassword=root在外围配置文件中引入 <properties resource="db.properties"> <property name="username" value="root"/> <property name="password" value="root"/> </properties>能够间接引入内部配置文件能够在其中减少以下属性配置如果两个文件有同一个字段,优先应用内部配置文件的!4、类型别名(typeAliases)类型别名可为 Java 类型设置一个缩写名字,它仅用于 XML 配置,意在升高冗余的全限定类名书写 <!--类型命名 能够给实体类起别名--> <!--<typeAliases></typeAliases>--> <typeAliases> <typeAlias type="com.aostarit.entity.User" alias="User"/> </typeAliases>也能够指定一个包名,Mybatis会在包名上面搜寻须要的Java Bean,比方:扫描实体类的包, 它的默认别名就是这个类的类名,首字母小写(大写能够,倡议小写)! <typeAliases> <!-- <typeAlias type="com.aostarit.entity.User" alias="User"/>--> <package name="com.aostarit.entity"/> </typeAliases>在实体类比拟少的时候,应用第一种形式,否则倡议应用第二种 如果实体类有注解,则别名为其注解值 @Alias("User")public class User {}5、设置(settings)6、其它配置 typeHandlers(类型处理器)objectFactory(对象工厂)plugins(插件)mybatis-generator-coremybatis-plus通用mapper7隐射器(mappers)MapperRegistry:注册绑定咱们的Mapper文件:形式一(举荐应用): <!--映射器--><mappers> <mapper resource="mapper/UserMapper.xml"/></mappers>应用二:应用class文件绑定注册 <mappers> <!-- <mapper resource="mapper/UserMapper.xml"/>--> <mapper class="com.aostarit.dao.UserMapper"/></mappers>留神点:接口和它的mapper配置文件必须同名接口和它的mapper配置文件必须在同一个包下形式三:应用扫描包进行注入绑定 <mappers> <!-- <mapper resource="mapper/UserMapper.xml"/>--> <!-- <mapper class="com.aostarit.dao.UserMapper"/>--> <package name="com.aostarit.dao"/></mappers>留神点:接口和它的mapper配置文件必须同名接口和它的mapper配置文件必须在同一个包下将数据库配置文件内部引入实体类别名保障UserMapper接口和UserMapper.xml改为统一!并且放在同一个包下

August 13, 2021 · 1 min · jiezi

关于mybatis:Mybatis实现增删改查

1、CRUD1.1namespacenamespace中的包名必须和Dao/mapper接口包名统一1.2select抉择,查问语句 id:就是对应的namespace中的办法名resultType:Sql语句执行的返回值类型parameterType:参数类型编写接口 User getUserById(int id);编写接口对应的Mapper中语句 <select id="getUserById" parameterType="int" resultType="com.aostarit.entity.User"> select * from mybatis.user where id = #{id}</select>测试: @Test public void getUserById() { //取得sqlSession对象 SqlSession sqlsession = MybatisUtil.getSqlsession(); //执行SQL UserMapper mapper = sqlsession.getMapper(UserMapper.class); User user = mapper.getUserById(1); System.out.println(user); //敞开sqlSession sqlsession.close(); }1.3Insert <!--对象中的属性能够间接取出来 --><insert id="addUser" parameterType="com.aostarit.entity.User"> insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd})</insert>1.4update <update id="updateUser" parameterType="com.aostarit.entity.User"> update mybatis.user set name = #{name},pwd = #{pwd} where id = #{id}</update>1.5delete <delete id="deleteUser" parameterType="int"> delete from mybatis.user where id = #{id}</delete>留神点:增删改查须要提交事务分许谬误: 标签不要匹配谬误:例如:select标签中必须写select语句resources绑定mapper,须要应用门路程序配置文件必须符合规范!NullPointException,没有注册到资源!输入的xml文件中存在中文乱码问题maven资源没有导出问题!mybatis外围配置文件中mapper映射器门路不能带.,须要用/代替<!--映射器--><mappers> <mapper resource="mapper/UserMapper.xml"/></mappers>2、Map和含糊查问拓展2.1假如咱们的实体类、或者数据库中的表、字段或者参数过多,咱们应该思考应用Map! ...

August 13, 2021 · 1 min · jiezi

关于mybatis:MyBatis三种批量插入方式的比较我推荐第3个

送大家以下java学习材料,文末有支付形式 数据库应用的是SQLServer,JDK版本1.8,运行在SpringBoot环境下 比照3种可用的形式 重复执行单条插入语句xml拼接sql批处理执行先说论断:大量插入请应用重复插入单条数据,不便。数量较多请应用批处理形式。(能够思考以有需要的插入数据量20条左右为界吧,在我的测试和数据库环境下耗时都是百毫秒级的,不便最重要)。 无论何时都不必xml拼接sql的形式。 代码拼接SQL的xmlnewId()是sqlserver生成UUID的函数,与本文内容无关 <insert id="insertByBatch" parameterType="java.util.List">    INSERT INTO tb_item VALUES    <foreach collection="list" item="item" index="index" separator=",">        (newId(),#{item.uniqueCode},#{item.projectId},#{item.name},#{item.type},#{item.packageUnique},        #{item.isPackage},#{item.factoryId},#{item.projectName},#{item.spec},#{item.length},#{item.weight},        #{item.material},#{item.setupPosition},#{item.areaPosition},#{item.bottomHeight},#{item.topHeight},        #{item.serialNumber},#{item.createTime}</foreach></insert>Mapper接口Mapper 是 mybatis插件tk.Mapper 的接口,与本文内容关系不大public interface ItemMapper extends Mapper<Item> {    int insertByBatch(List<Item> itemList);}Service类 @Servicepublic class ItemService {    @Autowired    private ItemMapper itemMapper;    @Autowired    private SqlSessionFactory sqlSessionFactory;    //批处理    @Transactional    public void add(List<Item> itemList) {        SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH,false);        ItemMapper mapper = session.getMapper(ItemMapper.class);        for (int i = 0; i < itemList.size(); i++) {            mapper.insertSelective(itemList.get(i));            if(i%1000==999){//每1000条提交一次避免内存溢出                session.commit();                session.clearCache();            }        }        session.commit();        session.clearCache();    }    //拼接sql    @Transactional    public void add1(List<Item> itemList) {        itemList.insertByBatch(itemMapper::insertSelective);    }    //循环插入    @Transactional    public void add2(List<Item> itemList) {        itemList.forEach(itemMapper::insertSelective);    }}测试类 @RunWith(SpringRunner.class)@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = ApplicationBoot.class)public class ItemServiceTest {    @Autowired    ItemService itemService;    private List<Item> itemList = new ArrayList<>();    //生成测试List    @Before     public void createList(){        String json ="{\n" +                "        \"areaPosition\": \"TEST\",\n" +                "        \"bottomHeight\": 5,\n" +                "        \"factoryId\": \"0\",\n" +                "        \"length\": 233.233,\n" +                "        \"material\": \"Q345B\",\n" +                "        \"name\": \"TEST\",\n" +                "        \"package\": false,\n" +                "        \"packageUnique\": \"45f8a0ba0bf048839df85f32ebe5bb81\",\n" +                "        \"projectId\": \"094b5eb5e0384bb1aaa822880a428b6d\",\n" +                "        \"projectName\": \"我的项目_TEST1\",\n" +                "        \"serialNumber\": \"1/2\",\n" +                "        \"setupPosition\": \"1B柱\",\n" +                "        \"spec\": \"200X200X200\",\n" +                "        \"topHeight\": 10,\n" +                "        \"type\": \"Steel\",\n" +                "        \"uniqueCode\": \"12344312\",\n" +                "        \"weight\": 100\n" +                "    }";        Item test1 = JSON.parseObject(json,Item.class);        test1.setCreateTime(new Date());        for (int i = 0; i < 1000; i++) {//测试会批改此数量            itemList.add(test1);        }    }     //批处理    @Test    @Transactional    public void tesInsert() {        itemService.add(itemList);    }    //拼接字符串    @Test    @Transactional    public void testInsert1(){        itemService.add1(itemList);    }    //循环插入    @Test    @Transactional    public void testInsert2(){        itemService.add2(itemList);    }}测试后果: 10条 25条数据插入经屡次测试,波动性较大,但根本都在百毫秒级别 其中 拼接sql形式在插入500条和1000条时报错(仿佛是因为sql语句过长,此条跟数据库类型无关,未做其余数据库的测试):com.microsoft.sqlserver.jdbc.SQLServerException: 传入的表格格局数据流(TDS)近程过程调用(RPC)协定流不正确,此RPC申请中提供了过多的参数,最多应为2100 能够发现 循环插入的工夫复杂度是 O(n),并且常数C很大拼接SQL插入的工夫复杂度(应该)是 O(logn),然而胜利实现次数不多,不确定批处理的效率的工夫复杂度是 O(logn),并且常数C也比拟小论断循环插入单条数据尽管效率极低,然而代码量极少,在应用tk.Mapper的插件状况下,仅需代码,: @Transactionalpublic void add1(List<Item> itemList) {    itemList.forEach(itemMapper::insertSelective);}因而,在需要插入数据数量不多的状况下必定用它了。 xml拼接sql是最不举荐的形式,应用时有大段的xml和sql语句要写,很容易出错,工作效率很低。更关键点是,尽管效率尚可,然而真正须要效率的时候你挂了,要你何用? 批处理执行是有大数据量插入时举荐的做法,应用起来也比拟不便。

August 9, 2021 · 1 min · jiezi

关于mybatis:Mybatis原理及源码分析

Mybatis原理及源码剖析作为Java程序员Mybatis应该是一个必会框架了,其源码体量只有Spring 的1/5,也是Hibernate的1/5 ,相比于其余风行框架Mybatis源码无疑是学习老本最低的,当做年轻人看的第一个框架源码,无疑是十分好的。 整体架构对于一个生疏的事物切勿一头扎进细节里,咱们先要观其大略看看架构脉络,MyBatis 分为三层架构,别离是根底撑持层、外围解决层和接口层。 Mybatis 整体架构 根底撑持层根底撑持层是这个Mybatis框架的基建,为整个Mybatis框架提供十分根底的性能。(篇幅无限上面咱们只对局部模块做简略的剖析) 类型转换模块,咱们在Mybatis中应用< typeAliase >标签定义一个别名就是应用类型转换模块实现的。类型转换模块最重要的性能还是实现了Mybatis中JDBC类型和Java类型之间的转换。次要体现在:在SQL模板绑定用户参入实参的场景中,将Java类型转换成JDBC类型在后果集中,将JDBC类型转换成Java类型。 Mybatis类型转换 日志模块,产生日志,定位异样。反射工具,对原生的Java反射作了一些封装。Binding模块,咱们在执行Mybatis中的办法时都是通过SqlSession来获Mapper接口中的代理,这个代理将Mapper.xml文件中SQL进行关联就是通过Binding模块来实现的。值得注意点是这个过程是产生在编译期。能够将谬误提前到编译期。数据源模块,数据源对于一个ORM来说算是十分外围的组件之一了。Mybatis默认的数据源是十分杰出的,Mybatis同时也反对集成第三方的数据源。缓存模块,缓存模块的好坏间接影响这个ORM的性能。Mybatis提供了两级缓存,同时也反对第三方缓存中间件集成。 Mybatis缓存 解析器模块,次要是config.xml配置文件解析,和mapper.xml文件解析。事务管理模块,事务模块对数据库的事务机制进行管制,对数据库事务进行了形象,同时也对spring框架进行了整合。具体的解决逻辑下文会联合源码具体解析。外围解决层外围解决层是咱们在学习Mybatis原理的时候须要花80%工夫的中央。外围解决层是 MyBatis 外围实现所在,其中波及 MyBatis 的初始化以及执行一条 SQL 语句的全流程。 配置解析MyBatis 的初始化以及执行一条 SQL 语句的全流程中也蕴含了配置解析,咱们在事实开发中个别都是应用spring boot starter的主动配置。咱们一我的项目启动为终点一层一层剥开Mybatis的流程。先关上org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration首先明确一点就是MybatisAutoConfiguration的目标就是要失去一个SqlSessionFactory。   @Bean  @ConditionalOnMissingBean  public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();    factory.setDataSource(dataSource);    factory.setVfs(SpringBootVFS.class);    if (StringUtils.hasText(this.properties.getConfigLocation())) {      factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));    }    Configuration configuration = this.properties.getConfiguration();    if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {      configuration = new Configuration();    }    if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {      for (ConfigurationCustomizer customizer : this.configurationCustomizers) {        customizer.customize(configuration);      }    }    factory.setConfiguration(configuration);    if (this.properties.getConfigurationProperties() != null) {      factory.setConfigurationProperties(this.properties.getConfigurationProperties());    }    if (!ObjectUtils.isEmpty(this.interceptors)) {      factory.setPlugins(this.interceptors);    }    if (this.databaseIdProvider != null) {      factory.setDatabaseIdProvider(this.databaseIdProvider);    }    if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {      factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());    }    if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {      factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());    }    if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {      factory.setMapperLocations(this.properties.resolveMapperLocations());    }    return factory.getObject();  }这里是通过MybatisProperties外面的配置并放入到SqlSessionFactoryBean中,再由SqlSessionFactoryBean失去SqlSessionFactory。看到最初一行return factory.getObject();咱们进去看看这个factory.getObject()的逻辑是如何失去一个SqlSessionFactory。 @Overridepublic SqlSessionFactory getObject() throws Exception {  if (this.sqlSessionFactory == null) {    afterPropertiesSet();  }  return this.sqlSessionFactory;}这一步没什么好说的,看看afterPropertiesSet()办法 @Overridepublic void afterPropertiesSet() throws Exception {  notNull(dataSource, "Property 'dataSource' is required");  notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");  state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),            "Property 'configuration' and 'configLocation' can not specified with together");  this.sqlSessionFactory = buildSqlSessionFactory();}重点来了,看看这个buildSqlSessionFactory()办法这里的外围目标就是将configurationProperties解析到Configuration对象中。代码太长了我就不贴出来了, buildSqlSessionFactory()的逻辑我画了个图,有趣味的小伙伴自行看一下。 Mybatis配置解析1 咱们不要陷入细节之中,咱们看看中点看看buildSqlSessionFactory() 办法的最初一行this.sqlSessionFactoryBuilder.build(configuration)点进去 public SqlSessionFactory build(Configuration config) {    return new DefaultSqlSessionFactory(config);  }通过buildSqlSessionFactory()解析失去的Configuration对象创立一个DefaultSqlSessionFactory(config),到此咱们就失去了SqlSessionFactory同时被配置成一个bean了。 咱们最终操作都是SqlSession,什么时候会通过SqlSessionFactory失去一个SqlSession呢?要解决这个问题咱们回到最开始的MybatisAutoConfiguration的sqlSessionTemplate(SqlSessionFactory sqlSessionFactory)这个办法,点开SqlSessionTemplate发现它是一个实现了SqlSession到这里咱们猜想就是在这里SqlSessionFactory会构建一个SqlSession进去。咱们进入new SqlSessionTemplate(sqlSessionFactory)看看源码。   public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {    this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());  }再往下看,咱们就看到了 public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,    PersistenceExceptionTranslator exceptionTranslator) {  notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");  notNull(executorType, "Property 'executorType' is required");  this.sqlSessionFactory = sqlSessionFactory;  this.executorType = executorType;  this.exceptionTranslator = exceptionTranslator;  this.sqlSessionProxy = (SqlSession) newProxyInstance(      SqlSessionFactory.class.getClassLoader(),      new Class[] { SqlSession.class },      new SqlSessionInterceptor());}这里通过动静代理创立了一个SqlSession。 参数映射、SQL解析咱们先看一下MapperFactoryBean类,这个类实现了FactoryBean在bean初始化的时候会调用getObject()办法咱们看看这个类下重写的getObject()办法里的内容。  @Override  public T getObject() throws Exception {    return getSqlSession().getMapper(this.mapperInterface);  }这里调用了sqlSession的getMapper()办法。一层一层点进去外面返回的是一个代理对象。最初的执行是由MapperProxy执行。 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);    if (mapperProxyFactory == null) {      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");    }    try {      return mapperProxyFactory.newInstance(sqlSession);    } catch (Exception e) {      throw new BindingException("Error getting mapper instance. Cause: " + e, e);    }  }接下来的流程我还是画个流程图,避免小伙伴们走丢。我这里的内容可能未必齐全和小标题一样,我次要依照sql执行的流程解说的。 Mybatis参数绑定 先看一下MapperProxy中的invoke办法,cachedMapperMethod()办法将MapperMethod缓存起来了。 @Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  try {    if (Object.class.equals(method.getDeclaringClass())) {      return method.invoke(this, args);    } else if (isDefaultMethod(method)) {      return invokeDefaultMethod(proxy, method, args);    }  } catch (Throwable t) {    throw ExceptionUtil.unwrapThrowable(t);  }  final MapperMethod mapperMethod = cachedMapperMethod(method);  return mapperMethod.execute(sqlSession, args);} private MapperMethod cachedMapperMethod(Method method) {    MapperMethod mapperMethod = methodCache.get(method);    if (mapperMethod == null) {      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());      methodCache.put(method, mapperMethod);    }    return mapperMethod;  }咱们在往下看mapperMethod.execute(sqlSession, args)办法。 public Object execute(SqlSession sqlSession, Object[] args) {  Object result;  switch (command.getType()) {    case INSERT: {    Object param = method.convertArgsToSqlCommandParam(args);      result = rowCountResult(sqlSession.insert(command.getName(), param));      break;    }    case UPDATE: {      Object param = method.convertArgsToSqlCommandParam(args);      result = rowCountResult(sqlSession.update(command.getName(), param));      break;    }    case DELETE: {      Object param = method.convertArgsToSqlCommandParam(args);      result = rowCountResult(sqlSession.delete(command.getName(), param));      break;    }    case SELECT:      if (method.returnsVoid() && method.hasResultHandler()) {        executeWithResultHandler(sqlSession, args);        result = null;      } else if (method.returnsMany()) {        result = executeForMany(sqlSession, args);      } else if (method.returnsMap()) {        result = executeForMap(sqlSession, args);      } else if (method.returnsCursor()) {        result = executeForCursor(sqlSession, args);      } else {        Object param = method.convertArgsToSqlCommandParam(args);        result = sqlSession.selectOne(command.getName(), param);      }      break;    case FLUSH:      result = sqlSession.flushStatements();      break;    default:      throw new BindingException("Unknown execution method for: " + command.getName());  }  if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {    throw new BindingException("Mapper method '" + command.getName()         + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");  }  return result;}method.convertArgsToSqlCommandParam(args)这里就是解决参数转换的逻辑。还有很多细节因为篇幅无限以及工夫仓促咱们不做过多的赘述,感兴趣的小伙伴能够联合下面的图本人看看。上面咱们看SQL的执行流程是怎么样的。整体流程如下图。 Mybatis执行流程 咱们就不对每一个执行器都剖析,我只挑一个SimpleExecutor来具体跟一下源码。咱们还是先看看图吧,避免本人把本人搞蒙。 以simpleExecutor为例的执行流程 @Overridepublic <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {  Statement stmt = null;  try {    Configuration configuration = ms.getConfiguration();    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);    stmt = prepareStatement(handler, ms.getStatementLog());    return handler.<E>query(stmt, resultHandler);  } finally {    closeStatement(stmt);  }}这里获取了Configuration,创立了一个StatementHandler,预处理操作,具体执行的依据创立的预处理办法,最初执行query办法 @Overridepublic <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {  String sql = boundSql.getSql();  statement.execute(sql);  return resultSetHandler.<E>handleResultSets(statement);}到此咱们整顿了整个Mybatis的执行流程,剖析了其中的源码,因为篇幅无限很多中央都没有粗疏的剖析,然而也贴出了图,心愿能帮忙到你。

August 8, 2021 · 1 min · jiezi

关于mybatis:Mybatis之复杂操作

最近在我的项目中遇到一些之前没有遇到的查问,以及实现,心愿能帮忙到工作中帮忙到正在求解的你们。1.JSON数组查问,针对mysql5.7及以上版本,数据库字段类型为JSON类型。查问json数组下标为0的元素(批量)json_extract SELECT d.id, d.name, d.name as equipment_name, d.code, d.sn_code, d.model_code, d.city_code, d.district_code, d.install_unit_code, d.bid_unit_code, d.repair_unit_code, m.category_code, m.pattern, m.name AS model_name, m.brand_code, d.warranty, d.warranty as guarantee_period, d.warranty_status, d.warranty_time, d.gmt_created, d.gmt_modified, d.created_by, d.modified_by, d.school_code, d.build_code, d.house_num, d.status FROM device_device d join device_model m on d.model_code = m.code <where> <if test="arrayStatus != null and arrayStatus.length >0"> AND json_extract(d.device_status,'$[0]') in <foreach collection="arrayStatus" item="item" index="index" open="(" separator="," close=")"> #{item} </foreach> </if> </where> 2.查问JSON字段某个符合要求的元素JSON_CONTAINS <select id="queryRoom" resultType="com.yuxiang.intelligence.dao.dataobject.AreaSchoolDO"> select * from `area_school` <where> <if test="schoolList != null and schoolList.size >0"> and organization_code in <foreach collection="schoolList" item="schoolCode" open="(" separator="," close=")" index="index"> #{schoolCode} </foreach> </if> <if test="floorCode != null and floorCode != ''"> and floor_code = #{floorCode} </if> <if test="houseNum != null and houseNum != ''"> and JSON_CONTAINS(`area_room`,JSON_OBJECT('houseNum', #{houseNum})) </if> <if test="dictionaryCode != null and dictionaryCode != ''"> and JSON_CONTAINS(`area_room`,JSON_OBJECT('dictionaryCode', #{dictionaryCode})) </if> </where> order by organization_code desc </select>3.依据汇合编号进行更新<update id="updateStatusBatch" parameterType="java.lang.Integer"> update `device_device` <trim prefix="set" suffixOverrides=","> <trim prefix="device_status =case" suffix="end"> <foreach collection="list" item="item" index="index"> <if test="item.code!=null"> when code=#{item.code} then #{item.deviceStatus} </if> </foreach> </trim> </trim> where code in <foreach collection="list" separator="," item="item" index="index" open="(" close=")"> #{item.code} </foreach> </update>4.依据汇合对象批量更新when then ...

August 3, 2021 · 2 min · jiezi

关于mybatis:SpringBoot-Mybatis系列Mapper接口注册的几种方式

【SpringBoot + Mybatis系列】Mapper接口注册的几种形式SpringBoot我的项目中借助Mybatis来操作数据库,对大部分java技术栈的小伙伴来说,并不会生疏;咱们晓得,应用mybatis,个别会有上面几个 Entity: 数据库实体类Mapper: db操作接口Service: 服务类本片博文中的注解,放在Mapper上,你晓得注册Mapper有几种形式么(这个问题像不像"茴"字有几个写法) <!-- more --> I. 环境筹备1. 数据库筹备应用mysql作为本文的实例数据库,新增一张表 CREATE TABLE `money` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名', `money` int(26) NOT NULL DEFAULT '0' COMMENT '钱', `is_deleted` tinyint(1) NOT NULL DEFAULT '0', `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创立工夫', `update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新工夫', PRIMARY KEY (`id`), KEY `name` (`name`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;2. 我的项目环境本文借助 SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA进行开发 ...

July 26, 2021 · 3 min · jiezi

关于mybatis:从代码生成说起带你深入理解-mybatis-generator-源码

干燥的工作这所有都要从多年前说起。 那时候刚入职一家新公司,项目经理给我调配了一个比较简单的工作,为所有的数据库字段整顿一张元数据表。 因为很多接手的我的项目文档都不全,所以须要对立整顿一份根本的字典表。 如果是你,你会怎么解决这个工作呢? 反复的工作一开始我是间接筹备人工把所有的字段整顿一遍,而后整顿出对应的 SQL 插入到元数据库治理表中。 meta_table 元数据表信息 meta_field 元数据字段信息 一开始还有点激情,起初就是无尽的反复,感觉非常无聊。 于是,我本人入手写了一个开源的小工具。 https://github.com/houbb/metadata元数据管理metadata 能够主动将所有的表信息和字段信息存入元数据表中,便于对立查阅。 (正文须要保障库自身曾经蕴含了对于表和字段的正文) 数据库表设计一开始实现了 3 种常见的数据库:mysql oracle sql-server。 以 mysql 为例,对应的建表语句为: drop table if exists meta_field;drop table if exists meta_model;/*==============================================================*//* Table: meta_field *//*==============================================================*/create table meta_field( ID int not null auto_increment comment '自增长主键', uid varchar(36) comment '惟一标识', name varchar(125) comment '名称', dbObjectName varchar(36) comment '数据库表名', alias varchar(125) comment '别名', description varchar(255) comment '形容', isNullable bool comment '是否可为空', dataType varchar(36) comment '数据类型', createTime datetime comment '创立工夫', updateTime datetime comment '更新工夫', primary key (ID))auto_increment = 1000DEFAULT CHARSET=utf8;alter table meta_field comment '元数据字段表';/*==============================================================*//* Table: meta_model *//*==============================================================*/create table meta_model( ID int not null auto_increment comment '自增长主键', uid varchar(36) comment '惟一标识', name varchar(125) comment '名称', dbObjectName varchar(36) comment '数据库表名', alias varchar(125) comment '别名', description varchar(255) comment '形容', category varchar(36) comment '分类', isVisible bool comment '是否可查问', isEditable bool comment '是否可编辑', createTime datetime comment '创立工夫', updateTime datetime comment '更新工夫', primary key (ID))DEFAULT CHARSET=utf8;alter table meta_model comment '元数据实体表';数据初始化metadata 是一个 web 利用,部署启动后,页面指定数据库连贯信息,就能够实现所有数据的初始化。 ...

July 22, 2021 · 7 min · jiezi

关于mybatis:mybatis操作Oracle数据库如何指定NLSLANGUAGE多语言

一、背景笔者碰到利用零碎连贯Oracle数据库时多语言须要对立应用英语,该配置不能在数据库Server端批改,因些须要在利用零碎端想方法进行配置。二、解决形式通过查阅数据源和mybatis相干源码,有两种形式反对批改:1、应用Druid数据源的配置项connectionInitSqls定义连贯初始化语句:connectionInitSqls: ["ALTER SESSION SET NLS_LANGUAGE='AMERICAN'"]2、不批改数据源配置,在利用零碎端减少mybatis的拦截器,拦截器代码如下:(1)、Spring boot的Bean配置@Configurationpublic class MybatisPlusConfig { /** * 更改会话状态 * * @return */@Beanpublic AlterSessionInterceptor alterSessionInterceptor() { return new AlterSessionInterceptor();}/** * 乐观锁插件 * * @return */@Beanpublic CustomOptimisticLockerInterceptor optimisticLockerInterceptor() { return new CustomOptimisticLockerInterceptor();}/** * oracle Sequence主键 * * @return */@Beanpublic OracleKeyGenerator oracleKeyGenerator() { return new OracleKeyGenerator();}} (2)、拦截器代码:@Slf4j@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})public class AlterSessionInterceptor implements Interceptor { @Overridepublic Object intercept(Invocation invocation) throws Throwable { Object[] args = invocation.getArgs(); Connection connection = (Connection) args[0]; if ("Oracle".equalsIgnoreCase(connection.getMetaData().getDatabaseProductName())) { Statement statement = null; try { statement = connection.createStatement(); String locale = RequestHelper.getCurrentLocale(); if ("en_GB".equalsIgnoreCase(locale)) { statement.execute("ALTER SESSION SET NLS_LANGUAGE='AMERICAN'"); } else { statement.execute("ALTER SESSION SET NLS_LANGUAGE='SIMPLIFIED CHINESE'"); } } finally { statement.close(); } } return invocation.proceed();}@Overridepublic Object plugin(Object target) { if (target instanceof StatementHandler) { return Plugin.wrap(target, this); } return target;}@Overridepublic void setProperties(Properties properties) { // to do nothing}三、计划比照1、在数据源配置,一次性配置,不必批改代码,所有用户都全副看到的错误信息全部都是英文提醒2、在代码进行拦挡解决,须要批改代码,可针对不同的用户显示不同语言版本的谬误提醒,然而每次执行语句时,都须要多执行一句设置语言版本语句,操作繁琐,影响性能 ...

July 14, 2021 · 1 min · jiezi

关于mybatis:MuBatis框架的使用解析数据库相关API的基本介绍

动静SQLif依据条件蕴含where子句的一部分 <select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = 'ACTIVE' <where> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </where></select>紧接着 < where > 的第一个条件不要加AND choose-when-otherwise不应用所有的条件,只是想从多个条件中抉择一个应用 <select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = 'ACTIVE' <choose> <when tset="title != null"> AND title like #{title} </when> <when test="author != null and author.name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose></select>wherewhere元素只会在子元素返回内容的状况下才会插入WHRER的子语句若子语句的结尾为AND或者OR,where元素会将这些去除 ...

July 11, 2021 · 3 min · jiezi

关于mybatis:练习mybatis多对一关系

多个学生,对应一个老师对于学生这边而言,关联, 多个学生,关联一个老师【多对一】对于老师而言,汇合,一个老师有很多学生【一对多】SQL: CREATE TABLE `teacher` (`id` INT(10) NOT NULL,`name` VARCHAR(30) DEFAULT NULL,PRIMARY KEY (`id`)) ENGINE=INNODB DEFAULT CHARSET=utf8INSERT 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);测试环境搭建1.导入lombok2.新建实体类Teacher,Student ...

June 21, 2021 · 1 min · jiezi

关于mybatis:Mybatis注解CRUD

1、CRUD咱们能够在工具类创立的时候实现主动提交事务! public class MybatisUtils{ private static SqlSessionFactory sqlSessionFactory; static{ try{ //应用Mybatis第一步:获取sqlSessionFactory对象 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); }}2.编写接口 public interface UserMapper{ @Select("select * from user") List<User> getUsers(); @Select("select * from user where id=#{id}") User getUserById(@Param("id") int id); @Insert("insert into user(id,name,pwd) values(#{id},#{name},#{pwd})") int addUser(User user); @Update("update user set name=#{name},pwd=#{pwd} where id=#{id}") int updateUser(User user); @Delete(delete from user where id=#{uid}) int deleteUser(@Param("uid") int id);}3.编写外围配置文件 ...

June 20, 2021 · 1 min · jiezi

关于mybatis:Mybatis使用注解开发

1、应用注解开发1.1、面向接口编程大家之前都学过面向对象编程,也学习过接口,但在真正的开发中,很多时候咱们会抉择面向接口编程根本原因:解耦 ,可拓展 ,进步复用 ,分层开发中 ,.下层不必管具体的实现 ,大家都恪守独特的规范 ,使得开发变得容易,规范性更好在一个面向对象的零碎中,零碎的各种性能是由许许多多的不同对象合作实现的。在这种状况下,各个对象外部是如何实现本人的,对系统设计人员来讲就不那么重要了;而各个对象之间的协作关系则成为零碎设计的要害。小到不同类之间的通信,大到各模块之间的交互,在零碎设计之初都是要着重思考的,这也是零碎设计的次要工作内容。面向接口编程就是指依照这种思维来编程。对于接口的了解 接口从更深层次的了解,应是定义(标准,束缚)与实现(名实拆散的准则)的拆散。接口的自身反映了零碎设计人员对系统的形象了解。接口应有两类:第一-类是对一个个体的形象,它可对应为一一个个形象体(abstract class);第二类是对一个个体某- 方面的形象,即造成一 个形象面(interface) ;一个体有可能有多个形象面。形象体与形象面是有区别的。三个面向对区别 面向对象是指,咱们思考问题时,以对象为单位,思考它的属性及办法面向过程是指,咱们思考问题时,以一个具体的流程(事务过程)为单位,思考它的实现接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题.更多的体现就是对系统整体的架构1.2注解开发1.注解在接口办法上实现 public interface UserDao{ @Select("select * from user") List<User> getUsers();}2.mybatis外围配置文件mabatis-config.xml <!--绑定接口--><mappers> <mapper class="com.jialidun.dao.UserDao"/></mappers>3.测试 @Testpublic void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); //底层次要利用反射 UserMapper mapper = sqlSession.getMapper(UserDap.class); List<User< userList = mapper.getUsers(); for(User user : userList){ System.out.println(user); } sqlSession.close(); }实质:反射机制实现底层:动静代理模式! 执行流程

June 20, 2021 · 1 min · jiezi

关于mybatis:Mybatis的RowBounds分页

RowBounds分页不再应用SQL实现分页1.接口 List<User> getUserByRowBounds();2.mapper.xml <select id="getUserByRowBounds" resultMap="UserMap"> select * from mybatis.user</select>3.测试 @Testpublic void getUserByRowBounds(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); //RowBounds实现 RowBounds rowBounds = new RowBounds(1,2); //通过java代码层面实现分页 List<User> userList = sqlSession.selectList("com.jialidun.dao.UserDap.getUserByRowBounds",null,rowBounds); for(User user:userList){ System.out.println(user); } sqlSession.close();}

June 20, 2021 · 1 min · jiezi

关于mybatis:SQL分页查询

1、分页思考:为什么要分页? 缩小数据的处理量应用Limit分页 #语法:SELECT * FROM `user` LIMIT startIndex,pageSize;# [0,3]SELECT * FROM `user` LIMIT 3;应用Mybatis实现分页,外围SQL1.接口 //分页List<User> getUserByLimit(Map<String,Integer> map);2.Mapper.xml <resultMap id="UserMap" type="User"> <!--column数据库中的字段,property实体类中的属性--> <result column="id" property="id"/> <result column="name" property="name"/> <result column="pwd" property="password"/></resultMap><select id="getUserByLimit" parameterType="map" resultMap="UserMap"> select * from mybatis.user limit #{startIndex},#{pageSize}</select>3.测试 @Testpublic void getUserByLimit(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserDao.class); Map<String,Integer> map = new HashMap<>(); map.put("startIndex",0); map.put("pageSize",2); List<User> userList = mapper.getUserByLimit(map); for(User user:userList){ System.out.println(user); } //敞开 sqlSession.close(); }

June 20, 2021 · 1 min · jiezi

关于mybatis:作用域Scope和生命周期

不同作用域和生命周期类别是至关重要的,因为谬误的应用会导致十分重大的并发问题。SqlSessionFactoryBuilder: 这个类能够被实例化、应用和抛弃,一旦创立了 SqlSessionFactory,就不再须要它了。局部变量SqlSessionFactory: 说白了就是能够设想为:数据库连接池SqlSessionFactory 一旦被创立就应该在利用的运行期间始终存在,没有任何理由抛弃它或从新创立另一个实例。因而 SqlSessionFactory 的最佳作用域是利用作用域。最简略的就是应用单例模式或者动态单例模式。SqlSession: 连贯到连接池的一个申请SqlSession 的实例不是线程平安的,因而是不能被共享的,所以它的最佳的作用域是申请或办法作用域。用完之后必须敞开,否则造成很大的内存资源开销!这里的每一个mapper,就代表每一个具体的业务!

June 20, 2021 · 1 min · jiezi

关于mybatis:Mybatis配置解析

1、外围配置文件mybatis-config.xmlMybatis的配置文件蕴含了会深深的影响Mybatis行为的设置和属性信息 configuration(配置)properties(属性)settings(设置)typeAliases(类型别名)typeHandlers(类型处理器)objectFactory(对象工厂)plugins(插件)environments(环境配置)environment(环境变量)transactionManager(事务管理器)dataSource(数据源)databaseIdProvider(数据库厂商标识)mappers(映射器)1.1、新建maven我的项目编写工具类 package com.jialidun.utils;//sqlSessionFactory--->sqlSessionpublic class MybatisUtils{private static SqlSessionFactory sqlSessionFactory;static{try{ //应用mybatis第一步:获取sqlSessionFactory对象 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); }catch(IOException e){ e.printStackTrace(); }}//既然有了 SqlSessionFactory,顾名思义,咱们能够从中取得 SqlSession 的实例。//SqlSession 提供了在数据库执行 SQL 命令所需的所有办法。public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession();}}实体类 package com.jialidun.pojo;@Datapublic class User{private int id;private String name;private String pwd;}接口 package com.jialidun.dao;public interface UserDao{ //查问全副用户List<User> getUserList();//依据id查问用户User getUserById(int id);//insert 一个用户int addUser(User user);//批改用户int updateUser(User user);//删除用户int deleteUser(int id);}mapper.xml映射文件 <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace=绑定一个对应的Dao/Mapper接口--><mapper namespace="com.jialidun.dao.UserDao"> <!--select查问语句--><select id="getUserList" resultType="com.jialidun.pojo.User">select * from mybatis.user</select><select id="getUserById" parameterType="int" resultType="user">select * from mybatis.user where id = #{id}</select><!--对象中的属性,能够间接取出来--><insert id="addUser" parameterType="com.jialidun.pojo.User"> insert into mybatis.user(id,name,pwd) values(#{id},#{name},#{pwd});</insert><update id="updateUser" parameterType="com.jialidun.pojo.User"> update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id};</update><delete id="deleteUser" parameterType="int"> delete from mybatis.user where id=#{id};</delete></mapper>测试 ...

June 19, 2021 · 2 min · jiezi

关于mybatis:map

假如,咱们的实体类,或者数据库中的表,字段或者参数过多,咱们该当应用Map! User addUser(Map<String,Object> map);<!--对象的属性,能够间接取出来传递map的key--><insert id="addUser" parameterType="map"> insert into mybatis.user(id,name,pwd) values (#{userId},#{userName},#{password});</insert>测试 @Testpublic void addUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); Map<String,Object> map = new HashMap<String,Object>(); map.put("userId",5); map.put("password","123789"); mapper.addUser(map); sqlSession.close();}map传递参数,间接在sql中取出map中的key即可!对象传递参数,间接在sql中取对象的属性即可!只有一个根本类型参数的状况下,能够间接在sql中取到! List<User> getUserLike(String value);<select id="getUserLike" resultType="com.jialidun.pojo.User"> select * from mybatis.user where name like "%" #{value} "%"/select>@Testpublic void getUserLike(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); List<User> userList = mapper.getUserLike("孙"); for(User user:userList){ System.out.println(user); } sqlSession.close();}

June 19, 2021 · 1 min · jiezi

关于mybatis:Mybatis程序入门案例

思路:搭建环境--->导入Mybatis--->编写代码--->测试 1.1、搭建环境搭建数据库 create databases if not exists `mybatis`;use `mybatis`;create table if not exists `user`( `id` int(20) not null, `name` varchar(30) default null, `pwd` varchar(30) default null, primary key(`id`))engine=innodb default charset=utf8;插入数据 insert into `user`(`id`,`name`,`pwd`) values(1,'孙悟空','123456'),(2,'猪八戒','111222'),(3,'唐僧','789456');新建我的项目1.新建一个一般的maven我的项目2.删除src目录3.导入maven依赖 <dependencies> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency></dependencies><!--在build中配置resources,来避免咱们资源导出失败的问题--><build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources></build>1.2、创立一个模块编写Mybaris的外围配置文件 ...

June 19, 2021 · 2 min · jiezi

关于mybatis:Mybatis

环境: JDK1.8MySQL5.7maven3.6.1Idea回顾:JDBCMySQLJava根底MavenJunit框架:配置文件。最好的形式:看官网文档 1、简介1.1、什么是Mybatis MyBatis 是一款优良的长久层框架它反对自定义 SQL、存储过程以及高级映射。MyBatis 罢黜了简直所有的 JDBC 代码以及设置参数和获取后果集的工作。MyBatis 能够通过简略的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,一般老式 Java 对象)为数据库中的记录。MyBatis 本是apache的一个开源我的项目iBatis, 2010年这个我的项目由apache software foundation 迁徙到了google code,并且改名为MyBatis 。2013年11月迁徙到Github。如何取得Mybatis? maven仓库: <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version></dependency>Github:https://github.com/mybatis/my...中文文档:https://mybatis.org/mybatis-3...1.2、长久化数据长久化 长久化就是将程序的数据在长久状态和刹时状态转化的过程长久状态就是在数据库里保留,只有数据库不删库刹时状态:内存断电即失数据库(JDBC),IO文件长久化。为什么须要长久化? 有一些对象,不能让他丢掉。内存太贵了 1.3、长久层Dao层,Service层,Controller层 实现长久化工作的代码块层界线非常显著 1.4、为什么学习Mybatis?不便传统的JDBC代码太简单了,简化,框架。长处:简略易学灵便sql和代码的拆散,进步了可维护性提供映射标签,反对对象与数据库的ORM字段关系映射提供对象关系映射标签,反对对象关系组建保护提供xml标签,反对编写动静sql

June 19, 2021 · 1 min · jiezi

关于mybatis:整合Mybatis

步骤:1.导入相干jar包 junitmybatismysql数据库spring相干的aop织入mybatis-spring1、新建一个maven我的项目<dependencies> <!--单元测试包--> <denpendency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!--mysql--> <denpendency> <groupId>mysql</groupId> <artifactId>mysql-connerctor-java</artifactId> <version>5.1.47</version> </dependency> <!--mybatis--> <denpendency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!--spring--> <denpendency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!--Spring操作数据库的话,还须要一个spring-jdbc--> <denpendency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!--aop织入--> <denpendency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version> </dependency> <!--mybatis-spring整合--> <denpendency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.2</version> </dependency> </dependencies><build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources></build>2.编写配置文件 3.测试 1.1、回顾Mybatis1.编写实体类 package com.jialidun.pojo;import lombok .Data;@Datapublic class User{ private int id; private String name; private String pwd;}2.编写外围配置文件mybatis-config.xml ...

June 19, 2021 · 1 min · jiezi

关于mybatis:真香警告Alibaba珍藏版-mybatis-手写文档刷起来

谈起MyBatis,我先提个问:什么是 MyBatis ?MyBatis 是反对定制化 SQL、存储过程以及高级映射的优良的长久层框架。MyBatis 防止了简直所有的 JDBC 代码和手动设置参数以及获取后果集。MyBatis 能够对配置和原生Map应用简略的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,一般的 Java对象)映射成数据库中的记录... 而明天咱要聊的就是Alibaba珍藏版mybatis手写文档,刷到的敌人真香正告呀! 申明:篇幅无限,Alibaba珍藏版mybatis手写文档还有一些面试解析+脑图等等,说的都不是很认真,但可分享源文档给刷到此文的敌人,收藏刷起来(点击下载)!珍藏版(1)——Mybatis入门1.什么是MyBatis 2.为什么咱们要用Mybatis? 3.Mybatis疾速入门 3.1 导入开发包3.2筹备测试工作3.3 创立mybatis配置文件3.4 编写工具类测试是否获取到连贯3.5 创立实体与映射关系文件3.6 编写DAO4.Mybatis工作流程 5.实现CRUD操作 5.1 减少学生5.2 依据ID查问数据5.3 查问所有数据5.4 依据id删除5.5 批改5.6 小细节5.7 Mybatis分页6.动静SQL 6.1 动静查问6.2 动静更新6.3 动静删除6.4 动静插入7.入门总结 珍藏版(2)——Mybatis配置信息1.映射文件 1.1 占位符1.2 主键生成策略1.2.1 UUID1.3 主键返回1.4 resultMap1.5 resultMap和resultType区别1.6 应用resultMap1.7 resultType和resultMap用法总结1.8 Mybatis映射文件解决特殊字符2.配置文件 2.1 别名2.2 Mapper加载2.3 提早加载2.4 提早加载测试3.配置相干总结 珍藏版(3)——关联映射1.Mybatis【多表连贯】 1.1—对一 1.1.1 设计表1.1.2 实体1.1.3 映射文件1.1.4 DAO层1.2—对多 1.2.1 设计数据库表1.2.2 实体1.2.3 映射文件SQL语句1.2.4 DAO1.3多对多 ...

May 30, 2021 · 1 min · jiezi

关于mybatis:Mybatis单表增删改查抽取

在日常开发中,针对mybatis单表的增删改查咱们能够提取进去或者采纳mybatisplus 抽取公共Dao接口public interface IBaseDao<T> { int deleteByPrimaryKey(Long id); int insert(T t); int insertSelective(T t); T selectByPrimaryKey(Long id); int updateByPrimaryKeySelective(T t); int updateByPrimaryKey(T t);}抽取公共Servicepublic interface IBaseService<T> { int deleteByPrimaryKey(Long id); int insert(T t); int insertSelective(T t); T selectByPrimaryKey(Long id); int updateByPrimaryKeySelective(T t); int updateByPrimaryKey(T t);}public abstract class BaseServiceImpl<T> implements IBaseService<T>{ public abstract IBaseDao<T> getBaseDao(); @Override public int deleteByPrimaryKey(Long id) { return getBaseDao().deleteByPrimaryKey(id); } @Override public int insert(T t) { return getBaseDao().insert(t); } @Override public int insertSelective(T t) { return getBaseDao().insertSelective(t); } @Override public T selectByPrimaryKey(Long id) { return getBaseDao().selectByPrimaryKey(id); } @Override public int updateByPrimaryKeySelective(T t) { return getBaseDao().updateByPrimaryKeySelective(t); } @Override public int updateByPrimaryKey(T t) { return getBaseDao().updateByPrimaryKey(t); }}之后咱们写的Mapper接口须要继承IBaseDao<?>,Service层接口须要继承IBaseService<?>并补上泛型,实现类除了实现接口还须要继承BaseServiceImpl,并重写getBaseDao()办法返回对应的mapper接口,这样根本的增删改查咱们就不必写了。 ...

May 26, 2021 · 1 min · jiezi

关于mybatis:MybatisPlus的应用场景及注入SQL原理分析

一、背景1.1 传统Mybatis的弊病1.1.1 场景形容假如有两张表:一张商品表、一张订单表,具体表的字段如下: 现有如下需要: 别离依据id查问商品表和订单表所有信息依据领取状态和告诉状态查问订单表信息对订单表减少一个订单状态,依据订单状态查问订单信息1.1.2 需要需要a:依据id查问商品表: @Select(" SELECT p.id ,p.name ,p.picture ,p.type ,p.price, p.type, p.time FROM product p where id = #{id} ")List<Product> getProductsBYId(@Param("id") Integer id);依据id查问订单表所有信息: @Select(" SELECT o.id ,o.pay_no ,o.user_id ,o.product_id ,o.pay_price, o.num, o.pay_time, o.order_type, o.notif_type FROM order o where id = #{id} ")List<Order> getOrderBYId(@Param("id") Integer id);需要b:依据领取状态和告诉状态查问订单表信息 @Select(" SELECT o.id ,o.pay_no ,o.user_id ,o.product_id ,o.pay_price, o.num, o.pay_time, o.order_type, o.notif_type FROM order o where order_type= #{orderType} ")List<Order> getOrderBYId(@Param("orderType") Integer orderType); @Select(" SELECT o.id ,o.pay_no ,o.user_id ,o.product_id ,o.pay_price, o.num, o.pay_time, o.order_type, o.notif_type FROM order o where notify_type= #{notifyType} ")List<Order> getOrderBYId(@Param("notifyType") Integer notifyType);需要c:对订单表减少一个订单状态status,依据订单状态查问订单信息。 ...

May 25, 2021 · 2 min · jiezi

关于mybatis:mybatis基础之一Mybatis的介绍和基本使用

1、数据库操作框架的历程(1) JDBC JDBC(Java Data Base Connection,java数据库连贯)是一种用于执行SQL语句的Java API,能够为多种关系数据库提供对立拜访,它由一组用Java语言编写的类和接口组成.JDBC提供了一种基准,据此能够构建更高级的工具和接口,使数据库开发人员可能编写数据库应用程序 长处:运行期:快捷、高效毛病:编辑期:代码量大、繁琐异样解决、不反对数据库跨平台 (2) DBUtils DBUtils是Java编程中的数据库操作实用工具,玲珑简略实用。 DBUtils封装了对JDBC的操作,简化了JDBC操作,能够少写代码。 DBUtils三个外围性能介绍 1、QueryRunner中提供对sql语句操作的API 2、ResultSetHandler接口,用于定义select操作后,怎么封装后果集 3、DBUtils类,它就是一个工具类,定义了敞开资源与事务处理的办法 (3)Hibernate Hibernate 是由 Gavin King 于 2001 年创立的凋谢源代码的对象关系框架。它弱小且高效的构建具备关系对象持久性和查问服务的 Java 应用程序。 Hibernate 将 Java 类映射到数据库表中,从 Java 数据类型中映射到 SQL 数据类型中,并把开发人员从 95% 的公共数据持续性编程工作中解放出来。 Hibernate 是传统 Java 对象和数据库服务器之间的桥梁,用来解决基于 O/R 映射机 Hibernate 劣势 Hibernate 应用 XML 文件来解决映射 Java 类别到数据库表格中,并且不必编写任何代码。为在数据库中间接贮存和检索 Java 对象提供简略的 APIs。如果在数据库中或任何其它表格中呈现变动,那么仅须要扭转 XML 文件属性。形象不相熟的 SQL 类型,并为咱们提供工作中所相熟的 Java 对象。Hibernate 不须要应用程序服务器来操作。操控你数据库中对象简单的关联。最小化与拜访数据库的智能提取策略。提供简略的数据询问。 Hibernate劣势 hibernate的齐全封装导致无奈应用数据的一些性能。Hibernate的缓存问题。Hibernate对于代码的耦合度太高。Hibernate寻找bug艰难。Hibernate批量数据操作须要大量的内存空间而且执行过程中须要的对象太多 ...

May 16, 2021 · 6 min · jiezi

关于mybatis:MyBatis源码解析一

MyBatis作为一个风行的半自动ORM框架,外面交融了许多优良的设计理念,剖析其源码骨架可能帮你建设良好的我的项目设计教训。因为其比较复杂,我会分成几篇来讲,一起踏上驯服的旅程吧! 首先把MyBatis源码包导入到idea,再新建一个我的项目依赖本地包,这样咱们就能够进行调试调用了。 因为MyBatis不同于Tomcat,它依赖于内部调用能力启动. MyBatis的根底撑持层基于iBatis,它在iBatis的根底上减少了外观模式,不便编码人员更直观的应用。 因而,咱们看一下它的外围包: 优良的中央在于,每个模块之间的耦合度较低,一个包就是一个独自的模块。所以咱们在剖析单个模块的时候,相干类都会在同一个包中,是不是很不便。 日志模块MyBatis没有提供日志的实现类,仅仅提供了一个Log接口,规定了trace、debug、warn、error四个级别: public interface Log { boolean isDebugEnabled(); boolean isTraceEnabled(); void error(String s, Throwable e); void error(String s); void debug(String s); void trace(String s); void warn(String s);}此处咱们以log4j来看,MyBatis是怎么集成日志插件的: 咱们关上这个Log4jImpl,看看它是怎么把日志插件集成进来的: 首先,它实现了Log接口,而后将Log的相干解决转交给Logger对象(log4j中理论的打印类)来解决,典型的适配器模式。其余的日志插件也是如此,能够看一下Log模块的类图: 这是一个工厂模式,通过它的工厂代码咱们就能够看到日志插件的加载程序: 当执行数据库操作的时候,就会打印出相应的日志: 那么问题来了,咱们在代码中并没有写打印语句呀,它是在哪里调用的呢? 这就是MyBatis的优良之处,真正做到了业务与技术拆散。

May 8, 2021 · 1 min · jiezi

关于mybatis:四动态-SQLSQL-语句构建器笔记

1、if <select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG <where> <if test="state != null"> state = #{state} </if> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </where></select>or<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG where 1=1 <if test="state != null"> state = #{state} </if> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if></select>2、choose、when、otherwise <select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <choose> <when test="title != null"> AND title like #{title} </when> <when test="author != null and author.name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose></select>3、trim、set<trim prefix="" suffix="" suffixOverrides="" prefixOverrides=""></trim>prefix: 增加前缀suffix: 增加后缀suffixOverrides: 去除前缀prefixOverrides: 去除后缀 ...

April 30, 2021 · 3 min · jiezi

关于mybatis:三XML配置文件笔记

cache – 该命名空间的缓存配置。cache-ref – 援用其它命名空间的缓存配置。resultMap – 形容如何从数据库后果集中加载对象,是最简单也是最弱小的元素。sql – 可被其它语句援用的可重用语句块。insert – 映射插入语句。update – 映射更新语句。delete – 映射删除语句。select – 映射查问语句。1、select - 映射查问语句 <select id="selectPerson" parameterType="int" resultType="hashmap" resultMap="personResultMap" flushCache="false" #将其设置为 true 后,只有语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。 useCache="true" #将其设置为 true 后,将会导致本条语句的后果被二级缓存缓存起来,默认值:对 select 元素为 true。 timeout="10" #这个设置是在抛出异样之前,驱动程序期待数据库返回申请后果的秒数。默认值为未设置(unset)(依赖数据库驱动)。 fetchSize="256" #这是一个给驱动的倡议值,尝试让驱动程序每次批量返回的后果行数等于这个设置值。 默认值为未设置(unset)(依赖驱动) statementType="PREPARED" #可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 别离应用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 resultSetType="FORWARD_ONLY"> #FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖数据库驱动)。 2、insert、update、delete <insert id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" keyProperty="" #(仅实用于 insert 和 update)指定可能惟一辨认对象的属性,MyBatis 会应用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,能够用逗号分隔多个属性名称。 keyColumn="" #(仅实用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,能够用逗号分隔多个属性名称。 useGeneratedKeys="" #(仅实用于 insert 和 update)这会令 MyBatis 应用 JDBC 的 getGeneratedKeys 办法来取出由数据库外部生成的主键(比方:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的主动递增字段),默认值:false。 timeout="20"> ...

April 30, 2021 · 1 min · jiezi

关于mybatis:二配置笔记

联合springBoot以及独自应用mybatis来验证一波 ,这几个问题在前面都会进行解说,先看了文档在说 对象工厂插件的应用多环境配置 https://mybatis.org/mybatis-3... 事务处理器 配置文件 configuration(配置) properties(属性)settings(设置)typeAliases(类型别名)typeHandlers(类型处理器)objectFactory(对象工厂)plugins(插件)environments(环境配置)environment(环境变量)transactionManager(事务管理器)dataSource(数据源)databaseIdProvider(数据库厂商标识)mappers(映射器)一、properties(属性) 1、这些属性能够在内部进行配置,并能够进行动静替换。 你既能够在典型的 Java 属性文件中配置这些属性,也能够在 properties 元素的子元素中设置。例如: <properties resource="org/mybatis/example/config.properties"> <property name="username" value="dev_user"/> <property name="password" value="F2Fa3!33TYyg"/></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>这个例子中的 username 和 password 将会由 properties 元素中设置的相应值来替换。2、MyBatis 3.4.2 开始,你能够为占位符指定一个默认值。 <dataSource type="POOLED"> <!-- ... --> <property name="username" value="${username:ut_user}"/> <!-- 如果属性 'username' 没有被配置,'username' 属性的值将为 'ut_user' --></dataSource>这个个性默认是敞开的。要启用这个个性,须要增加一个特定的属性来开启这个个性。例如: <properties resource="org/mybatis/example/config.properties"> <!-- ... --> <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/> <!-- 启用默认值个性 --></properties>3、 批改默认值的分隔符 <properties resource="org/mybatis/example/config.properties"> <!-- ... --> <property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="?:"/> <!-- 批改默认值的分隔符 --></properties>后果 <dataSource type="POOLED"> <!-- ... --> <property name="username" value="${db:username?:ut_user}"/></dataSource>二、设置settings <settings> <setting name="cacheEnabled" value="true"/> #全局性地开启或敞开所有映射器配置文件中已配置的任何缓存。默认true <setting name="lazyLoadingEnabled" value="true"/> #提早加载的全局开关特定关联关系中可通过设置 fetchType 属性来笼罩该项的开关状态。 <setting name="multipleResultSetsEnabled" value="true"/> #是否容许单个语句返回多后果集(须要数据库驱动反对)。 <setting name="useColumnLabel" value="true"/> #应用列标签代替列名。理论体现依赖于数据库驱动,具体可参考数据库驱动的相干文档,或通过比照测试来察看。 <setting name="useGeneratedKeys" value="false"/> #容许 JDBC 反对主动生成主键,须要数据库驱动反对。如果设置为 true,将强制应用主动生成主键。只管一些数据库驱动不反对此个性,但仍可失常工作(如 Derby) <setting name="autoMappingBehavior" value="PARTIAL"/> #指定 MyBatis 应如何主动映射列到字段或属性。 NONE 示意敞开主动映射;PARTIAL 只会主动映射没有定义嵌套后果映射的字段。 FULL 会主动映射任何简单的后果集(无论是否嵌套) <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/> #指定发现主动映射指标未知列(或未知属性类型)的行为。 none 不做任何行为(默认)Warning 输入正告日志 failing 映射失败 <setting name="defaultExecutorType" value="SIMPLE"/> #配置默认的执行器。SIMPLE 就是一般的执行器;REUSE 执行器会重用预处理语句(PreparedStatement); BATCH 执行器不仅重用语句还会执行批量更新。 <setting name="defaultStatementTimeout" value="25"/> #设置超时工夫,它决定数据库驱动期待数据库响应的秒数。 <setting name="defaultFetchSize" value="100"/> #为驱动的后果集获取数量(fetchSize)设置一个倡议值。此参数只能够在查问设置中被笼罩。 <setting name="safeRowBoundsEnabled" value="false"/> #是否容许在嵌套语句中应用分页(RowBounds)。如果容许应用则设置为 false。 默认false <setting name="mapUnderscoreToCamelCase" value="false"/>#是否开启驼峰命名主动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 <setting name="localCacheScope" value="SESSION"/> #MyBatis 利用本地缓存机制(Local Cache)避免循环援用和减速反复的嵌套查问。 默认值为 SESSION,会缓存一个会话中执行的所有查问。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对雷同 SqlSession 的不同查问将不会进行缓存。 <setting name="jdbcTypeForNull" value="OTHER"/> #当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型。 某些数据库驱动须要指定列的 JDBC 类型,少数状况间接用个别类型即可,比方 NULL、VARCHAR 或 OTHER。 <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>#指定对象的哪些办法触发一次提早加载。</settings> 三、类别名(typeAliases)类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在升高冗余的全限定类名书写。例如:<typeAliases> <typeAlias alias="Author" type="domain.blog.Author"/> <typeAlias alias="Blog" type="domain.blog.Blog"/> <typeAlias alias="Comment" type="domain.blog.Comment"/> <typeAlias alias="Post" type="domain.blog.Post"/> <typeAlias alias="Section" type="domain.blog.Section"/> <typeAlias alias="Tag" type="domain.blog.Tag"/></typeAliases> ...

April 30, 2021 · 3 min · jiezi

关于mybatis:一Mybatis简介入门相关对象作用域笔记

内容来源于官网:https://mybatis.org/mybatis-3/zh/configuration.html 一、入门简介简介:MyBatis 是一款优良的长久层框架,它反对自定义 SQL、存储过程以及高级映射。MyBatis 罢黜了简直所有的 JDBC 代码以及设置参数和获取后果集的工作。 每个基于 MyBatis 的利用都是以一个 SqlSessionFactory 的实例为外围的。SqlSessionFactory 的实例能够通过 SqlSessionFactoryBuilder 取得。而 SqlSessionFactoryBuilder 则能够从 XML 配置文件或一个事后配置的 Configuration 实例来构建出 SqlSessionFactory 实例。 阐明:工厂模式:工厂类模式提供的疾速的创立单个类的模式 ,工厂只负责创立出对象,具体的办法须要你本人去实现。建造者模式:通过传入具体对象 调用了具体定义的办法,建造者负责传递对象和指定对象调用何种办法。 导入依赖: <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>x.x.x</version></dependency>https://my.oschina.net/u/3995... 1、从xml中读取配置文件构建连贯 <?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>public class TestMyBatis { public static void main(String[] args) { try { // 根本mybatis环境 // 1.定义mybatis_config文件地址 String resources = "mybatis_config.xml"; // 2.获取InputStreamReaderIo流 Reader reader = Resources.getResourceAsReader(resources); // 3.获取SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); // 4.获取Session SqlSession sqlSession = sqlSessionFactory.openSession(); // 5.操作Mapper接口 count=sqlSession.selectOne("com.bdqn.dao.TUserMapper.queryCount"); System.out.println(count); } catch (Exception e) { e.printStackTrace(); } }}读取配置文件,配置文件转化为流,通过SqlSessionFactoryBuilder解决传入的配置文件对象,再将解决过后的配置文件对象传给sqlSessionFactory,配置文件包含数据源和数据库事务 去生成sqlsession对象。sqlseesion对象则可用来操作mapper接口了。 ...

April 30, 2021 · 2 min · jiezi