# mybatis **Repository Path**: xgdtianxian/mybatis ## Basic Information - **Project Name**: mybatis - **Description**: mybatis案例 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2023-09-20 - **Last Updated**: 2024-04-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README Mybatis 一.概念 Mybatis 是-个半自动的ORM 框架用于简化开发者对数据库的操作过程。 二 快速入门三使用方式 a。基于StatementId: 1创建Maven项目 2添加mybatis的依赖(mybatis 和 mysql) 3创建对应的库表以及实体类 4.添加mybaits核心配置,用于配置数据库链接 5.创建mybatis映射文件(mapper.xml),此方式下映射文件放在resources下任意目录 6.再核心配置文件中,添加映射文件 7.编写测试类 进行测试 b.基于接口绑定 1-4相同 5.创建 接口用于执行表的crud,并且添加对应的抽象方法。 6.创建 xxxMapper.xml 要求:xml要和接口再同一目录下 namespace要和接口的完整限定名一样 映射文件的的crud的id要和接口的方法名一样 7.核心配置中添加 mapper接口的路径 mapper class 或者 package 8. sqlSession.getMapper(Mapper.class)进行测试 c。基于注解 1-4同上 5.创建接口,并在接口的方法上添加对应的注解 @Select @Update @Delete @Insert 6.核心配置文件,添加mapper class 7.测试 ps: 接口绑定方式和注解可以同时使用,但接口的方法不能同时注解和映射文件。 三。mybatis核心配置文件 主要负责管理数据源,映射文件以及mybatis在工作下的一些行为。 Configuration根节点 生成Configuration对象 environments 配置各种不同的数据库环境 default属性:配置 environment 配置具体的数据库环境 id 起名字 environment具体的一个环境 id transactionManager:mybatis的事务管理。 表示使用 JDBC默认的事务管理(Connection 实现) MANAGED 表示不使用事务 dataSource 配置数据源 type="POOLED/UNPOOLED" 设置是否使用连接池 mappers 配置映射文件 只用于 statementId方式操作Mybatis properties resource=引入外部属性资源文件(db.properties) 在核心配置中 用 ${key} settings 配置 mybatis工作时的一些特性 useColumnLabel true/false 是否允许在sql语句中,使用别名来映射对象的属性. mapUnderscoreToCamelCase false/true 是否开启 数据库的列名的蛇形命名法 到 java对象 属性名(驼峰命名法)的映射 typeAliases 配置别名,在映射文件mapper中,可以简写参数类型和结果类型 package name="bean包路径" typeAlias type="java类型" alias="别名" databaseIdProvider 用于给不同的数据库起一个标识,在mapper.xml的crud中使用 databaseId可以进行绑定 四 映射文件配置 增删改配置 id:表示唯一和接口中的方法名绑定 parameterType: 用于告知传入的参数的类型(可以不写) timeout: 设置方法执行超时时间 statementType: 设置mybatis使用哪种操作对象执行sql STATEMENT:相当于 jdbc里的 Statement,直接拼接sql语句执行 占位符 ${} PREPARED : 相当于 PreparedStatement ,支持预加载 防sql注入 占位符 #{} ${} CALLABLE: 调用存储过程 useGeneratedKeys 配合 keyProperty 实现: 当执行 添加或者 修改语句时,把自动生成的主键,放回参数对象中指定的属性中去。 databaseId 数据库厂商表示,表示这条语句是给哪种数据库使用. 参数处理 参数处理:mybatis xml文件获取参数的方式 方式1 #{} 会把sql语句中所有的 #{} 换成? 预编译,再通过PreparedStatement 把用户提供的参数给设置到 ?当中 防止sql注入。 方式2 ${} 不进行预编译,直接把用户提供的参数 放入sql语句中,不进行预处理 存在sql注入的风险 使用场景 动态列或者动态表操作 参数传递方式: 1.如果mapper接口的参数 是一个 简单型(8种基本型 包装类 String Date) a.在#{} 随便写 b.如果给 参数起了别名( 接口的形参前加上 @Param("别名") ) ,#{}只能写 别名 param1 2.参数为 一个对象 a. 在#{} 直接写对象的属性名 (不能用 形参.属性名) b. 起了别名 #{别名.属性} #{param1.属性} 3.参数为多个简单型 a. 在#{} 写 arg0, arg1 / param1,param2(不推荐) b. 起别名 #{别名} #{别名} 别名不能一样 / 或 param1,param2(不推荐) 4.参数为多个对象或者多个简单型混搭时 a. #{} arg 0 1 2,param1,2,2,3. 对象参数 arg0.属性名 (不推荐) b. 别名 #{别名.属性} #{别名} 5.当参数为一个数组时 a. #{array[脚标]} #{arg0[脚标]} b. 别名 #{别名[脚标]} 6. 当参数为一个List集合 a. #{list[0]} #{collection[0]} #{arg0[0]} b. 别名, #{别名[0]} 7. 当参数为一个Map集合时 a. #{key} b. 别名 #{别名.key} 或者 #{别名[key]} 结果处理 Mybatis有多种方式和配置来接受数据库执行增删改查之后的结果。 1.查询结果为1条数据时 方式一: 用pojo对象直接来接受 接口的返回值为对应的POJO (User Emp Book) xml: resultType也用pojo 方式二: 使用Map 来接受查询结果 接口的返回值为 Map xml resultType = map ps:map中 key为查询结果 每一列的列名,值为对应列的列值 2. 查询数据为多条时 方式一: 用List来接受 接口返回值: List xml: resultType = POJO ps: xml中的 大于号使用 > 小于号 使用 < 或者 方式二: 用List> 接口返回: List> xml: resultType = map 3. 查询结果为 一个 简单数据时 用简单数据对应的数据类型来接受即可 接口: 简单数据类型(int String float double) xml: 简单数据类型(或它的别名) 一般用于查询结果为 聚合函数的结果时。 4. 自定义映射结果 自行定义映射规则,查询结果的哪一列,对应实体类的哪一个属性。一般用于列名和属性名不一样的场景。 主键列映射 //用于非主键列的映射 补充:mybatis中如何使用模糊查询 1. SELECT * FROM emp WHERE empName like "%${}%" 存在 sql注入的风险 2. SELECT * FROM emp WHERE empName like #{} 在传参时 参数中带上 %张% 3. SELECT * FROM emp WHERE empName LIKE CONCAT("%",#{关键字},"%") 传参时只需要传入 关键字即可 高级映射 一:多对一映射 方式1:(使用扩展类) 1.搞清谁是多的一方,谁是一的一方。 2.创建多的一方的扩展类(Vo,DTO),补充1的一方的属性即可。 3.在映射文件中配置,扩展类的映射规则即可。 方式2: 嵌套结果 1.分析谁是多和一 2.在多的一方里 体现 一的一方的存在,即一的一方以属性的形式出现在多的一方的实体类中 3.在映射文件里,通过association 配置1的一方的映射 //剩下的列 怎么映射成一的一方的对象。 方式三: 嵌套查询 ps:扩展类和嵌套结果,本质上是一条查询出结果 嵌套查询:分开的两条查询,得到结果并进行映射。 1.分析多和一 2.多的一方加一的一方的属性 3.配置 一的一一方的查询方法 mapper/xml 4.在多的一方的查询语句,只查自身表的数据 5.配置映射规则 二:一对多映射 方式一: 嵌套结果 1.分析一和多 2.在一的一方的中,维护多的一方的属性(private List xxxx) 3.在一的一方的 xml文件中 配置resultMap 使用 配置多的一方的映射规则 (id result) 4.在一的一方中,查询语句使用 多表查询 方式二: 嵌套查询 1.分析一和多 2.在一的一方,维护多的属性(private List xxxx) 3.给多的一方,提供查询的发方法,一般是用一的一方的主键列作为查询条件。 4.在一的一方的配置文件中,resultMap 5.在一的一方中,查询语句单表查询。 动态SQL mybatis xml映射文件中的一个方法(crud),根据传递的参数不同,生成不同结构的sql语句。 常用节点: sql的片段 只有当if成立时,sql片段才会被拼接到xml中。 //一些判断 WHERE节点会自动的生成一个WHERE语句(无实质内容时,不生成) 会自动的去掉 第一个条件前面的 AND / OR 片段 prefix 会在片段前增指定内容 prefixOverrides 会把片段最前面的指定内容删除 suffix 在片段的末尾追加内容 suffixOverrides 删除片段末尾的指定内容 //判断 set节点会自动生成条 SET语句,并且会自动去掉末尾"," 片段1 片段2 片段3 choose when otherwise 相当于 if(条件1){ 片段1 }else if(条件2){ 片段2 }else{ 片段3 } #{别名} foreach 可以用于遍历 数组类型的参数 ps:每遍历出一个数据,会在foreach中加上分割符,但最后一个元素之后不会加。 bind可以放在 select/update/delete/insert 节点中, 用于通过表达式,给一个变量名赋值,就可以在这些节点中以#{变量名}来直接使用。 一部分会被经常使用到的sql代码 sql片段 引用指定的sql片段 批量添加数据 方式一:mapper中的添加,一次添加一条数据,多次调用。 优化: 配置mybatis的执行器 ExecutorType SIMPLE 不做任何处理,预处理对象(PreparedStatement) 反复的被创建和销毁。 REUSE 预处理对象创建一次后,被重复利用。 BATCH 同上,并对多次添加做了优化(不做单次添加方法返回) 方式二:mapper中的添加方法中,一次添加多条数据 INSERT INTO ..values (),(),() [性能最佳] 方式三: mapper中的添加方法中,包含多条inert语句 insert into....; insert into....; jdbc:mysql://....?allowMultiQueries=true mysql配置允许一个方法执行多条查询 mysql> set global max_allowed_packet=14600000; 设置mysql接受的数据包的最大值。 Mybatis缓存 什么是缓存: 缓存是一种存储数据的机制,是把数据临时的存储在内存上,读写更快,减少硬盘上数据库的压力。 ps:内存上的数据,重启后就消失了。 什么数据使用缓存: 1.数据字典(不经常改变的数据 ) 省 市 部门。。。 2.并发量比较大的数据,先存在缓存上,等高峰过了,再存入数据库。 3.分布式锁:分布式session 4.不需要持久化的临时数据:比如验证码 mybatis一级缓存: 1.默认开启 2.作用域 基于sqlSession,离开了本次sqlSession 就会失效。 关闭一级缓存 默认值SESSION 开启 3.一级缓存失效: a.不同的sqlSession b.同一个sqlSession,但是查询语句不一样 c.如果中间执行了 增删改操作(不管是不是同一张表) d.手动清空 sqlSession.clearCache() 4 一级缓存的实现: PerpetualCache 对象中 有一个cache属性 map用来存储查询到的数据 key:hashCode+查询语句命名空间+sql语句 value:查询到的结果 从一级缓存取数据其实就是从map里通过key 取数据 二级缓存: 1.默认开启 核心: 2.二级缓存作用域为全局(SqlSessinFactory)级别,随着应用的开启而开启,随着应用的销毁而销毁。 3.二级缓存存储的对象,需要实现可序列化接口Serializable,并且需要在对应的mapper中 添加 cache节点 4.事务提交(commit或者close)的时候,查询的数据才会存放到二级缓存 5.一个mapper文件对应 一个二级缓存。 6.当查找数据时,会先从二级缓存查找,再从一级缓存,再从数据库查找。 7.二级缓存失效: a.当同一个命名空间 执行了 增删改 二级缓存失效,会重新查数据库。 ps:mapper中的增删改映射 可以配置 flushCache 配置是否更新二级缓存。 增删改默认为 true b.手动设置 某一个查询 不使用二级缓存 useCache false(默认为true) flushCache false (默认为false) c.其他的mapperB可以通过设置 表B执行增删改的时候,当前表A的二级缓存失效。 8.的属性: readOnly:true 当某表只涉及查询时,设置readOnly 可以增加二级缓存读的速度 flushInterval: 设置二级缓存 刷新的时间 毫秒 eviction:设置 二级缓存当中数据过多时,删除缓存的策略 LRU:会优先删除,最近使用用最少的二级缓存 /Least Recently Used FIFO:先存的二级缓存,会被先删除 / First In First Out SOFT:软引用 WEAK:弱引用 size:设置缓存存储对象的数量 Mybatis分页插件 1.使用流程: a.在pom.xml中 添加依赖 pageHelper b.在核心配置中配置分页插件 c.使用方式: 1. sqlSession.selectList("查询语句的id",查询的参数,new RowBounds(开始的条数,往后查多少条))。 2. 基于接口绑定 PageHelper.startPage(页号,页大) 它之后的下一条查询语句,会自动进行分页 BookMapper.selectAllBook(); 3. PageHelper.offsetPage("从第几条开始","多少条") 其他同2 4. 参数方法调用: 当分页插件发现 mapper接口中的方法 有别名是 pageNum 和pageSize的参数时,自动进行分页 (不需要手动在mapper.xml语句中添加 分页的语句) 插件中配置: 开启之后 List selectAllBook(@Param("pageNum") int pageNum,@Param("pageSize") int pageSize); 2.接受分页查询之后的结果 a. 直接在mapper接口中,用List接受 b. 接口中使用 Page 接受 (Page是ArrayList的 子类,可以像List一样直接使用) PageInfo info = page.toPageInfo();或者 PageInfo info = new PageInfo(page,导航页码的个数) pageInfo对象中包含分页的信息 getTotal() 总条数 getPageNum() 当前页码 getPageSize() 页面大小 getPages() 总页数 getNextPage() 下一页页码 0说明不存在 getPrePage() 上一页页码 0说明不存在 isHasNextPage() 是否有下一页 isHasPreviousPage() 是否有上一页 getNavigatePageNums() int[] 获取分页条的页码编号