免费做销售网站,马家堡做网站的公司,站群建站,品牌网站首页怎么设计1、引入日志
在这里我们引入SLF4J的日志门面#xff0c;使用logback的具体日志实现#xff1b;引入相关依赖#xff1a; !--日志的依赖--dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdversion使用logback的具体日志实现引入相关依赖 !--日志的依赖--dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdversion1.7.30/version/dependencydependencygroupIdch.qos.logback/groupIdartifactIdlogback-classic/artifactIdversion1.2.3/version/dependency添加logback的配置文件
?xml version1.0 encodingUTF-8?
configuration scantrue!--追加器日志以哪种方式输出name自定义追加器的名称class追加器实现类的全限定名不同实现类输出的方式不同下面是以控制台方式输出--appender nameCONSOLE classch.qos.logback.core.ConsoleAppenderencoder!--设置日志输出格式--pattern%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} --- %msg%n/patterncharsetUTF-8/charset/encoder/appender!--设置全局日志级别--root levelINFO!--设置当前日志级别输出到哪个追加器上--appender-ref refCONSOLE //root!--设置某个包或者某个类的局部日志级别--logger nameorg.example.mapper leveldebug /logger nameorg.apache.ibatis.transaction leveldebug //configuration测试结果
2、全局配置文件
在mybatis的项目中有一个mybatis-config.xml的配置文件这个配置文件是mybatis的全局配置文件用来进行相关的全局配置。
?xml version1.0 encodingUTF-8 ?
!DOCTYPE configuration PUBLIC -//mybatis.org//DTD Config 3.0//EN https://mybatis.org/dtd/mybatis-3-config.dtd
configurationproperties resourcedb.properties/propertiessettings /settingstypeAliases /typeAliasesenvironments/environmentsmappers/mappers
/configuration1、propertis属性 !--配置外部属性资源文件通过 ${} 来进行引用--properties resourcedb.properties!--也可以在内部自定义属性--property namedriver valuecom.mysql.cj.jdbc.Driver/property nameurl valuejdbc:mysql://localhost:3306/trs-db?useUnicodetrueamp;characterEncodingutf8amp;tinyInt1isBitfalseamp;useSSLfalseamp;serverTimezoneGMT%2B8amp;allowMultiQueriestrueamp;zeroDateTimeBehaviorconvertToNull/property nameusername valueroot/property namepassword valuerootxq//properties2、setting设置 settings!-- 设置默认执行器SIMPLE(普通执行器)、REUSE(可重复使用执行器会重用预处理语句)、BATCH(批量执行器不仅重用预处理语句而且可以批量更新)--setting namedefaultExecutorType valueSIMPLE/!-- 开启驼峰命名自动映射--setting namemapUnderscoreToCamelCase valuetrue/!-- 在懒加载下哪些方法会触发立即加载默认equals、toString、hashCode--!--setting namelazyLoadTriggerMethods value/--!-- 开启全局的延迟加载true 所有的嵌套查询都是懒加载false 所有嵌套查询都会被立即加载--setting namelazyLoadingEnabled valuetrue/!-- 设置加载的数据是否按需加载--setting nameaggressiveLazyLoading valuefalse/!-- 开启二级缓存--setting namecacheEnabled valuetrue//settings3、typeAliases类型别名 !--设置类的别名可以降低冗余的全局限定名的书写--typeAliases!--1、可以设置包下所有类的别名会使用类名作为别名是忽略大小写的--!--package nameorg.example.pojo/--!--2、可以自定义设置某个类的别名--typeAlias typeorg.example.pojo.Emp aliasemp/typeAlias typeorg.example.pojo.Dept aliasdept//typeAliases4、environments环境配置 !--配置数据源连接信息--!--可以配置多个数据源environment例如测试环境、生产环境各配置一个数据源default设置默认使用哪个数据源--environments defaultdevelopmentenvironment iddevelopment!--事务管理器type 设置事务管理类型1JDBC使用JDBC的事务管理方式2MANAGED不运用事务 --transactionManager typeJDBC/!--数据源type 设置数据源类型1UNPOOLED不使用连接池2POOLED使用Mybatis的连接池--dataSource typePOOLEDproperty namedriver value${db.driver}/property nameurl value${db.url}/property nameusername value${db.username}/property namepassword value${db.password}//dataSource/environment/environments5、mappers映射器 !--映射器有4种配置方式--mappers!--1、设置MapperXML的方式适用于根据statementId进行操作--mapper resourcemapper/DeptMapper.xml/mapper resourcemapper/EmpMapper.xml/!--2、设置Mapper接口的方式适用于接口绑定的方式--!--mapper classorg.example.mapper.EmpMapper/--!--mapper classorg.example.mapper.DeptMapper/--!--3、使用磁盘的绝对路径基本不用--!--4、根据包路径设置该包下的所有Mapper接口适用于接口绑定和注解的方式应用最多的方式--!--package nameorg.example.mapper/--/mappers3、SQL映射文件
MyBatis 的真正强大之处在于它的语句映射。由于它的异常强大映射器的XML 文件就显得相对简单。MyBatis 致力于减少使用成本让用户能更专注于 SQL 代码。映射文件中极其重要的几大标签 select映射查询语句insert映射插入语句update映射更新语句delete映射删除语句sql定义可重用的sql语句cache设置当前命名空间下的缓存配置cache-ref引用其他命名空间下的缓存配置resultMap描述如何从数据库的结果集中加载对象 每个顶级元素标签中可以添加很多个属性下面介绍相关属性的作用 1id设置当前命名空间中各个映射标签的唯一标识符同一个命名空间中的id不允许重复对应mapper接口中的方法名称2paramType设置SQL的参数类型mybatis会根据接口方法的参数自动读取参数的类型所以不强制要求设置3statementType设置当前的Statement类型默认为PREPARED: STATEMENT代表JDBC的Statement不支持参数预解析;PREPARED代表JDBC的PreparedStatement支持参数预解析;CALLABLE代表JDBC的CallableStatement支持存储过程调用; 4useGeneratedKeys启用主键生成策略设置是否获取插入后的自增长主键的值默认是false设置为true时才会获取自增长主键的值5keyProperty设置将获取到的自增长主键值映射到实体类的哪个属性上6keyColumn如果存在组合主键的情况指定获取哪个主键的字段名; 例如 insert idinsertEmp useGeneratedKeystrue keyPropertyeId !--如果数据库不支持列值自增长的话可以使用下面的方法selectKey可以在增删改操作之前或者之后执行相关属性order设置执行时机BEFORE表示之前AFTER表示之后keyProperty设置将当前查询结果放到哪个POJO的属性上resultType设置返回值的类型--selectKey orderBEFORE keyPropertyeId resultTypeintSELECT MAX(eid)1 FROM emp/selectKeyINSERT INTO emp (eid,e_name,e_mail,salary,did) values (#{eId},#{eName},#{eMail},#{salary},#{did})/insert4、基于XML的详细使用
POJO实体类public class Emp{private Integer eId;private String eName;private String eMail;private Double salary;private Integer did;
}public class Dept{private Integer did;private String dName;
}1、参数的获取方式
#{} sql “SELECT * FROM emp WHERE eid ?” a、会经过JDBC中的PreparedStatement对象进行预编译处理会根据不同的数据类型来编译成对应数据库所对应的数据类型; 例如String id “100010”#{id} sql SELECT * FROM emp WHERE eid ‘100010’; 例如Integer id 100010#{id} sql SELECT * FROM emp WHERE eid 100010;b、能够有效的防止SQL注入; ${} sql “SELECT * FROM emp WHERE eid ” id; a、不会进行预编译会直接将获取到的的参数直接拼接在sql中;b、存在SQL注入的风险特殊用法 1调试时可以临时使用这样可以直接将携带参数的完整sql语句打印在控制台 2需要动态拼接的时候可以使用${}但是要在保证数据的安全性的前提下操作;
2、参数的传递方式 单个参数的传递 1参数类型是普通数据类型时使用#{参数名称}来获取参数即#{id} public interface EmpMapper {Emp selectEmpById(Integer id);
}select idselectEmpById resultMapempResultSetselect * from emp where eid #{id}/select2参数类型是javaBean时使用#{属性名}来获取参数emp.eId #{eId}, emp.eName #{eName} public interface EmpMapper {Emp selectEmpInfo(Emp emp);}select idselectEmpInfo resultTypeorg.example.pojo.Empselect * from emp where eid #{eId} and e_name #{eName}/select3参数类型是数组或者list集合时mybatis会自动封装成map 数组{key:array,value:array}获取方式#{arg0.下标} 或者 #{array.下标}集合{key:list,value:list}获取方式#{arg0.下标} 或者 #{list.下标}如果方法中使用了Param()注解来指定别名则获取方式为#{别名.下标} public interface EmpMapper {ListEmp selectEmpByNames(ListString names);}select idselectEmpByNames resultTypeorg.example.pojo.Empselect * from emp where e_name in (#{arg0.0}, #{list.1}, #{arg0.2})
/select4参数类型是map集合时与javaBean的参数传递情况一样 public interface EmpMapper {Emp selectEmpByMap(MapString,Object paramMap);
}MapString, Object paramMap new HashMap();paramMap .put(id,1);paramMap .put(ename,lq);select idselectEmpByMap resultTypeorg.example.pojo.Empselect * from emp where eid #{id} and e_name #{ename}/select多个参数的传递 mybatis会对参数按顺序进行封装将参数封装成map集合 public interface EmpMapper {Emp selectEmpByIdAndName( Integer id, String ename);
}id {key : arg0value : id的值} 或者 {key : param1value : id的值}ename {key : arg1value : ename的值} 或者 {key : param2value : ename的值}可以使用#{key}来获取对应的值 select idselectEmpByIdAndName resultTypeorg.example.pojo.Empselect * from emp where eid #{arg0} and e_name #{param2}
/select可以给每个参数设置别名使其具有参数意义 语法使用注解Param(参数别名) public interface EmpMapper {Emp selectEmpByIdAndName( Param(id)Integer id, Param(ename)String ename);
}id #{id} 或者 #{param1}ename #{ename} 或者 #{param2}可以使用#{参数别名}来获取对应的值 select idselectEmpByIdAndName resultTypeorg.example.pojo.Empselect * from emp where eid #{id} and e_name #{ename}/select如果是参数类型既有普通数据类型又有javaBean时public interface EmpMapper {Emp selectEmpInfoByDid(Integer did,Param(emp) Emp emp);
}id #{param1} 或者 Param(“did”)emp.eName #{param2.eName} 或者 emp.eName注意多个参数时获取JavaBean中的属性时使用#{参数别名.属性名} select idselectEmpInfoByDid resultTypeorg.example.pojo.Empselect * from emp where did #{param1} and e_name #{emp.eName}/select3、处理返回结果
返回类型设置 如果返回单行数据可是使用Java基础数据类型或者POJO或者Map接收如果返回多行数据可以使用List POJO或者List Map 接收需要在resultType中指定List中的泛型类型; 当返回结果是集合的时候返回值的类型依然写的是集合中具体的类型 select idselectAllEmp resultTypeorg.example.pojo.Empselect * from emp/select在查询时可以设置返回值的类型为map当mybatis查询完成之后会把列的名称作为key列的值作为value转换到map中select idselectEmpByEmpReturnMap resultTypemapselect * from emp where empno #{empno}
/select4、自定义结果集
如果数据库表的字段与POJO的属性名不一致时除了可使用AS来设置别名还可以使用resultMap来设置自定义结果集注意resultType与resultMap二者只能使用其一。相关属性 id唯一标识需要与select标签中的resultMap进行关联type需要映射的Pojo类型autoMapping是否自动映射默认为false只要字段名与属性名遵循映射规则就可以自动映射extends如果同一命名空间内如果有多个resultMap有重复的映射可以声明父resultMap将公共的映射提取出来可以减少子resultMap的映射冗余 resultMap idempResultSet typeorg.example.pojo.Emp!--id用来指定主键字段的映射关系result用来指定普通字段的映射关系column需要映射的数据库表中字段的名称property需要映射的POJO中的属性名称--id columneid propertyeId/result columne_name propertyeName/result columne_mail propertyeMail/result columnsalary propertysalary/result columndid propertydid//resultMapselect idselectEmp resultMapempResultSetselect * from emp where did #{dept_id}/select5、高级结果映射
1、联合查询
public class EmpDeptDto extends Emp{private Dept dept;public Dept getDept() {return dept;}public void setDept(Dept dept) {this.dept dept;}Overridepublic String toString() {return super.toString() EmpDeptDto{ dept dept };}
}1、多对一映射
查询所有员工的信息以及对应的部门多员工同属一个部门
resultMap idempAndDeptMap extendsempResultSet typeorg.example.pojo.EmpDeptDto!--普通方式对象属性名.属性--!--result propertydept.dName columnd_name/--!--result propertydept.did columndid/--!--association方式会强行使我们的结果映射为多对一property指定的“一”javaType“一“的类型自定义映射的时候才需要指定与resultType二者使用其一resultMap调用已经存在的映射关系重用resultMapcolumnPrefix 如果出现两张表的字段有重复时则需要使用as来起别名可以给字段加上前缀在映射的时候可以使用columnPrefix自动将前缀去掉这样就能映射成功--association propertydept columnPrefixdept_ javaTypeorg.example.pojo.Dept resultMaporg.example.mapper.DeptMapper.baseDeptMap!--id propertydid columndid/--!--result propertydName columnd_name/--/association/resultMapselect idselectEmpAndDept resultMapempAndDeptMapSELECTe.*,d.did AS dept_did,d.d_name AS dept_d_nameFROMemp AS eLEFT JOIN dept AS d ON e.did d.did/select2、一对多映射
查询部门信息以及所属的员工信息一个部门包含多个员工
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttps://mybatis.org/dtd/mybatis-3-mapper.dtdmapper namespaceorg.example.mapper.DeptMapperresultMap idbaseDeptMap typeorg.example.pojo.Deptid columndid propertydid/result columnd_name propertydName//resultMap!--一对多映射关系property指定的“多”ofType“多”的类型自定义映射的时候才需要指定与resultType二者使用其一resultMap调用已经存在的映射关系重用resultMap无论是association还是collection都需要查询主键值--resultMap iddeptAndEmpMap extendsbaseDeptMap typeorg.example.pojo.DeptEmpDtocollection propertyemps ofTypeorg.example.pojo.Emp resultMaporg.example.mapper.EmpMapper.empResultSet!--也可以自定义映射关系--!--id columneid propertyeId/--!--result columne_name propertyeName/--!--result columne_mail propertyeMail/--!--result columnsalary propertysalary/--!--result columndid propertydid/--/collection/resultMapselect idgetDeptAndEmp resultMapdeptAndEmpMapSELECTd.*,e.*FROM dept d LEFT JOIN emp eON d.did e.did/select
/mapper2、嵌套查询
!--嵌套查询分步查询select查询关联对象的sql语句column需要传递的参数值的字段fetchType懒加载延迟查询嵌套查询的对象用到的时候才回去查询数据--resultMap idqueryDeptAndEmpMap typeorg.example.pojo.DeptEmpDto extendsbaseDeptMapcollection propertyemps fetchTypelazy selectorg.example.mapper.EmpMapper.selectEmp columndid//resultMapselect idqueryDeptAndEmp resultMapqueryDeptAndEmpMapselect * from dept/select3、延迟查询
当我们在进行表关联的时候有可能在查询结果的时候不需要关联对象的属性值那么此时可以通过延迟加载来实现功能。在全局配置文件中添加如下属性 !‐‐ 开启延迟加载所有分步查询都是懒加载 默认是立即加载‐‐setting namelazyLoadingEnabled valuetrue/!‐‐当开启式 使用pojo中任意属性都会加载延迟查询 ,默认是falsesetting nameaggressiveLazyLoading valuefalse/‐‐!‐‐设置对象的哪些方法调用会加载延迟查询 默认equals,clone,hashCode,toString‐‐setting namelazyLoadTriggerMethods value/如果设置了全局加载但是希望在某一个sql语句查询的时候不使用延时策略可以添加fetchType下属性; association propertydept columndept_id fetchTypeeager resultMaporg.example.mapper.DeptMapper.baseDeptMap/association6、动态SQL
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架你应该能理解根据不同条件拼接 SQL 语句有多痛苦例如拼接时要确保不能忘记添加必要的空格还要注意去掉列表最后一个列名的逗号。利用动态 SQL可以彻底摆脱这种痛苦。
如果出现SQL语句中因特殊字符报错的话可以使用转义字符或者![CDATA[]]来解决
1、动态SQL之if
语法 if test条件表达式 可以是OGNL表达式 /if作用完成简单的条件判断加载动态条件问题如果无法确定第一个条件是否成立导致无法确定是否拼接 and或者or 的拼接 1可以设置 11 避免报错2可以使用 where标签它会自动拼接或者删除and或者or3可以使用 trim标签 select idqueryEmps resultTypeorg.example.pojo.Empselect * from emp where 11if testsalary ! null and salary ! AND salary ![CDATA[]] #{salary}/ifif testeName ! null and salary ! AND e_name #{eName}/ifif testeId ! null and salary ! AND eid #{eId}/if /select2、动态SQL之where
语法 where /where作用如果存在条件则自动拼接where关键字也可以动态的删除条件语句中的and或者or select idqueryEmps resultTypeorg.example.pojo.Empselect * from emp whereif testsalary ! null and salary ! AND salary ![CDATA[]] #{salary}/ifif testeName ! null and salary ! AND e_name #{eName}/ifif testeId ! null and salary ! AND eid #{eId}/if/where/select3、动态SQL之trim
语法 trim prefix prefixOverrides suffix suffixOverrides /trim作用它的功能比较灵活、广泛可以在条件判断完的SQL语句前后添加或者去掉指定的字符相关属性 prefix前缀需要添加的前缀prefixOverrides需要去掉的前缀例如and|orsuffix后缀需要添加的后缀suffixOverrides需要去掉的后缀例如, select idqueryEmps resultTypeorg.example.pojo.Empselect * from emp trim prefixwhere prefixOverridesand|or suffix suffixOverridesif testsalary ! null and salary ! AND salary ![CDATA[]] #{salary}/ifif testeName ! null and salary ! AND e_name #{eName}/ifif testeId ! null and salary ! AND eid #{eId}/if/trim/select4、动态SQL之choose、when、otherwise
作用它有着类似于if、elseif、else的作用。 select idqueryEmps2 resultMapempResultSetselect * from empwherechoosewhen testeName lveid 1/whenwhen testeName zlqeid 2/whenotherwiseeid 3/otherwise/choose/where/select5、动态SQL之set
作用主要用于解决修改操作中SET关键字以及SQL语句中可能多出的逗号问题 update idupdateEmpupdate empsetif testeName ! null and eName ! e_name #{eName},/ifif testeMail ! null and eMail ! e_mail #{eMail},/ifif testsalary ! null and salary ! salary #{salary},/ifif testdid ! null and did ! did #{did},/if/setwhere eid #{eId}/update6、动态SQL之foreach
作用循环遍历集合或者数组相关属性 collection指定需要遍历的集合名称item每次遍历的集合元素index遍历时的下标separator分隔符open循环开始时添加的字符close循环结束时添加的字符 select idqueryEmpByNames resultMapempResultSetselect * from empwhere e_name inforeach collectionnames itemname indexi separator, open( close)#{name}/foreach/select7、动态SQL之sql片段
作用提取重复冗余的sql语句使其可以被共用相关属性 id唯一标识使用 include refid“sql片段的Id” /标签来引用 sql idquerySQLselect * from emp/sqlselect idselectEmpByMap resultTypeorg.example.pojo.Empinclude refidquerySQL/where eid #{id} and e_name #{ename}/select8、常用的OGNL表达式
1e1 or e2逻辑或2e1 and e2逻辑与3e1 ! e2 或者 e1 neq e2判断两个对象是否不相等4e1 e2 或者 e1 eq e2判断两个对象是否相等5e1 e2 或者 e1 gt e2判断e1是否大于e26e1 e2 或者 e1 gte e2判断e1是否大于等于e27e1 e2 或者 e1 lt e2判断e1是否小于e28e1 e2 或者 e1 lte e2判断e1是否小于等于e29e1 instanceof e2判断e1是否是e2的实例10e1.method(e2)调用e1对象的method方法并将e2作为参数传递给method方11e1 in e2判断e1是否在e2中12e1 not in e2判断e1是否不在e2中13e1 like e2判断e1是否和e2匹配13e1 not like e2判断e1是否和e2不匹配14e1 between e2 and e3判断e1是否在e2和e3之间15e1 not between e2 and e3判断e1是否不在e2和e3之间16e1 is null判断e1是否为null17e1 is not null判断e1是否不为null18!e1逻辑非19e1e2,e1-e2,e1*e2,e1/e2加减乘除
7、缓存
MyBatis 内置了一个强大的事务性查询缓存机制它可以非常方便地配置和定制。在进行配置的时候还会分为一级缓存和二级缓存 一级缓存线程级别的缓存是本地缓存sqlSession级别的缓存二级缓存全局范围的缓存不仅局限于当前会话
1、一级缓存
特性 1、默认开启也可以关闭一级缓存localCacheScopeSTATENENT2、作用域默认是基于sqlSession的就是一次数据库操作会话3、缓存默认的实现类是PerpetualCache使用map进行存储key hashcode sqlid sql hashcode environment的id4、查询完就会进行数据的缓存 失效情况 1、不同的sqlSession会使一级缓存失效2、同一个sqlSession但是查询语句不同也会使一级缓存失效3、同一个sqlSession查询语句相同但在中间过程中执行了增删改操作也会使一级缓存失效4、同一个sqlSession查询语句相同执行手动清除缓存会使一级缓存失效 例如
2、二级缓存
特性 1、默认开启但没有实现2、作用域是全局范围的存储到Java进程当中的如果线程过多会出现OOM3、缓存默认的实现类也是PerpetualCache使用map进行存储但是使用map存储的是二级缓存根据不同的mapper命名空间多包了一层的map。即keymapper的命名空间valueMapk,PerpetualCache.map4、提交事务时或者sqlSession关闭的时候进行数据缓存 实现 1、在全局配置文件中开启二级缓存 setting namecacheEnabled valuetrue/2、在需要用到二级缓存的mapper映射文件中加入 cache /cache它是基于Mapper映射文件来实现存储的. 查询顺序 先从二级缓存中获取再从一级缓存中获取如果都没有则查询数据库 失效情况 1、同一个命名空间下进行增删改操作会使二级缓存失效2、如果不想增删改操作后缓存被清空则可以给对应的增删改sql设置flushCachefalse但是设置要慎重因为会造成数据脏读问题。3、让查询到的数据不缓存到二级缓存中设置useCache“false” 即select idgetDeptById useCachefalse4、如果希望其他mapper映射文件的命名空间执行了增删改也清空另外的命名空间的缓存可以在某个命名空间下使用 cache-ref namespace/ 例如
8、分页插件
Mybatis通过提供插件机制让我们可以根据自己的需要去增强Mybatis的功能。Mybatis的插件可以在不修改原来代码的情况下通过拦截的方式改变四大核心对象的行为例如处理参数、处理SQL、处理结果等等Mybatis的分页默认是基于内存分页的查出所有再截取在数据量大的情况下效率较低不过使用mybatis插件可以改变该行为只需要拦截StatementHandler类的prepare方法改变要执行的SQL语句为分页语句即可
1、应用过程
1、添加依赖 !--mybatis分页插件依赖--dependencygroupIdcom.github.pagehelper/groupIdartifactIdpagehelper/artifactIdversion5.1.11/version/dependency2、插件注册
在mybatis-config.xml配置文件中进行注册 plugins!--注册分页插件--plugin interceptorcom.github.pagehelper.PageInterceptor!--设置当前数据库的方言默认会自动检查当前数据库环境实用的数据库--property namehelperDialect valuemysql/!--自动合理化设置分页参数--property namereasonable valuetrue/!--支持通过Mapper接口的参数来传递分页参数默认值为false,分页参数名称为pageNum、pageSize--property namesupportMethodsArguments valuetrue//plugin/plugins3、调用 select idqueryEmpList resultTypeorg.example.pojo.Empselect * from emp/selectTestpublic void testMybatis9(){EmpMapper mapper sqlSession.getMapper(EmpMapper.class);PageHelper.startPage(1,2);ListEmp emps mapper.queryEmpList();System.out.println(emps);//PageInfo对象中包含了很多分页相关的属性例如当前页总页数总记录数是否有上/下一页等等PageInfoEmp pageInfo new PageInfo(emps);pageInfo.getList().forEach(System.out::println);System.out.println(pageInfo.getTotal());System.out.println(Arrays.toString(pageInfo.getNavigatepageNums()));}2、代理和拦截的实现
四大对象什么时候被代理 Executor 是openSession()的时候创建的StatementHandler 是SimpleExecutor.doQuery()创建的里面包含了处理参数的ParameterHandler 和 处理结果集的ResultSetHandler 的创建创建之后即调用InterceptorChain.pluginAll()返回层层代理后的对象。代理是由Plugin 类创建。在我们重写的plugin() 方法里面可以直接调用returnPlugin.wrap(target, this);返回代理对象。因为代理类是Plugin所以最后调用的是Plugin 的invoke()方法。它先调用了定义的拦截器的intercept()方法。可以通过invocation.proceed()调用到被代理对象被拦截的方法。 调用流程时序图