导学

在之前的学习中,我们使用MyBatis进行了数据的CRUD操作,而且还学习了它里面一些开发小技巧。那么在本节课程中,我们将要学习MyBatis的一些高级特性。

MyBatis日志管理

日志接口jar包及其实现jar包

什么是日志?这个问题其实很简单,日志是对生活和工作的记录。
那么MyBatis的日志,实际上就是对MyBatis工作的记录,就如同飞机的黑匣子会记录飞机飞行产生的一切数据一样。我们可以使用MyBatis的日志,来记录和分析,应用程序使用过程中对数据库的操作及其影响,也是我们诊断问题和理解系统活动的重要依据。
通常日志是记录和保存在日志文件中的,同学们其实也接触过日志,就是我们在Tomcat使用过程中控制台所显示的那些内容。
其实,在Java中也可以通过第三方的日志的接口模块创建日志记录和文件,再由不同的jar包实现对应的接口模块,比如常用的有Comms-Logging=>log4jSLF4J=>logback等。
5.MyBatis进阶 - 图1
从目前的趋势来看,越来越多的开源项目从Commons-Logging加Log4j转向了SLF4J加logback。我们在使用日志记录的时候,需要注意项目中使用的是Commons-Logging还是SLF4J,虽然切换日志实现不会造成什么影响。比如SLF4J还是Commons-Logging,都可以使用logBack作为日志实现,但是它们的接口方法的定义还是不同的。

logback

早期的Java项目中,基本都是使用的log4j。但是,在本教程中我们将针对logback做着重的讲解。
因为log4j和logback是近亲,这两个日志管理实现都是由一个人开发的。英文log4j虽然经过多次更新迭代,仍然有些问题积重难返,所以作者另起炉灶开发了另一款日志管理实现logback,而且logback的性能要好的多。在MyBatis底层可以通过SLF4J支持logback!
代码实现:

  1. pom.xml增加依赖
    1. <dependency>
    2. <groupId>ch.qos.logback</groupId>
    3. <artifactId>logback-classic</artifactId>
    4. <version>1.2.3</version>
    5. </dependency>
    5.MyBatis进阶 - 图2
    其实此时,如果我们运行测试类中方法,就会发现在控制台中就会打印日志信息了。
    2. 对日志管理进行自定义设置
    在resources目录下新增logback.xml文件。注意,必须叫这个名字!
    1. <?xml version="1.0" encoding="UTF-8" ?>
    2. <configuration>
    3. <!-- 指定在控制台中输出日志 -->
    4. <!-- name属性可以随意,如果要在控制台输出,一般称之为console -->
    5. <!-- class属性指定何处打印输出 -->
    6. <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    7. <!-- 编码节点 -->
    8. <encoder>
    9. <!--
    10. %d{HH:mm:ss.SSS}:输出时间格式,精确到毫秒
    11. [%thread]:当前操作的线程
    12. %-5level:以5个字符右对齐以及级别
    13. %logger{36}:具体哪个类的日志(只显示36个字符)
    14. %msg:日志信息
    15. %n:换行
    16. 这些表达式在logback官网上都有详细说明
    17. -->
    18. <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    19. </encoder>
    20. </appender>
    21. <!--
    22. 日志输出级别(优先级高到低):
    23. error: 错误 - 系统的故障日志
    24. warn: 警告 - 存在风险或使用不当的日志
    25. info: 一般性消息
    26. debug: 程序内部用于调试信息
    27. trace: 程序运行的跟踪信息
    28. 下方root标签表示日志的最低输出级别为debug,即debug级别以下的信息不进行输出
    29. -->
    30. <root level="debug">
    31. <appender-ref ref="console"></appender-ref>
    32. </root>
    33. </configuration>

    MyBatis的动态SQL

    在我们使用SQL语句时,有的时候参数是不固定的。比如用户可以指定多个检索条件,也可能单独只指定一个检索条件。在这个时候,我们无法确定条件参数的数量,只能使用动态SQL完成。在实际的开发中,动态SQL的使用非常普遍。

    动态SQL是指根据参数数据动态组织SQL的技术,它有些类似于对SQL执行拼接。

可以使用<where>标签和<if>组合使用,或是单独使用<if>标签来实现动态SQL。

  1. <select id="dynamicSQL" parameterType="java.util.Map" resultType="com.dodoke.mybatis.entity.Goods">
  2. select * from t_goods
  3. <!-- 不需要写where关键字,只需要利用where标签智能判断and是否要添加 -->
  4. <where>
  5. <!-- 针对map中的key进行判断对应的value值是否为null和空 -->
  6. <if test="categoryId != null and categoryId!=''">
  7. and category_id = #{categoryId}
  8. </if>
  9. <if test="currentPrice != null and categoryId!=''">
  10. and current_price &lt; #{currentPrice}
  11. </if>
  12. </where>
  13. </select>
  1. /**
  2. * 动态SQL语句
  3. * @throws Exception
  4. */
  5. @Test
  6. public void testDynamicSQL() throws Exception {
  7. SqlSession session = null;
  8. try{
  9. session = MyBatisUtils.openSqlSession();
  10. Map param = new HashMap();
  11. param.put("categoryId", 44);
  12. param.put("currentPrice", 500);
  13. //查询条件
  14. List<Goods> list = session.selectList("com.dodoke.mybatis.resources.mappers.GoodsMapper.delete.dynamicSQL", param);
  15. for(Goods g:list){
  16. System.out.println(g.getTitle() + ":" +
  17. g.getCategoryId() + ":" + g.getCurrentPrice());
  18. }
  19. }catch (Exception e){
  20. throw e;
  21. }finally {
  22. MyBatisUtils.closeSqlSession(session);
  23. }
  24. }

MyBatis的缓存机制

在一个项目中,查询数据库中的操作算是一个非常常用的操作,但是有些数据会被经常性的查询,而每一次都去数据库中查询这些重复的数据,会很消耗数据库的资源,同时使得查询效率也很低。
而 MyBatis 中就通过缓存技术来解决这样的问题,也就是说:将一些经常查询,并且不经常改变的,以及数据的正确对最后的结果影响不大的数据,放置在一个缓存容器中,当用户再次查询这些数据的时候,就不必再去数据库中查询,直接在缓存中提取就可以了。

注:缓存可以简单理解为存在于内存中的临时数据

在MyBatis中,存在一级缓存和二级缓存,一级缓存的效果,可以体现为同一个sqlSession对象操作同一条SQL时,只要参数相同就不会再去进行数据库查询,一级缓存默认开启。二级缓存需要手动开启。
关于如何使用二级缓存,可以参考如下文章,这里不再赘述,各位同学自由补充。
参考文档:
https://zhuanlan.zhihu.com/p/106258135

MyBatis多表级联查询

MyBatis多表级联查询和之前学习的MyBatis多表关联查询不一样。

  • 多表关联查询:两个表通过主外键在一条SQL中完成所有数据的提取。
  • 多表级联查询:通过一个对象来获取与它关联的另外一个对象,执行的SQL语句分为多条。

确定对象之间的关系是双向的:
双向的一对多,应该变成多对多,在进行数据库设计的时候需要单独抽象出一张中间表来!!!
5.MyBatis进阶 - 图3

一对多关联查询

案例:要求查询某件商品的详细信息

  1. 新建实体类

    1. package com.dodoke.mybatis.entity;
    2. public class GoodsDetail {
    3. private Integer gdId;
    4. private Integer goodsId;
    5. private String gdPicUrl;
    6. private Integer gdOrder;
    7. public Integer getGdId() {
    8. return gdId;
    9. }
    10. public void setGdId(Integer gdId) {
    11. this.gdId = gdId;
    12. }
    13. public Integer getGoodsId() {
    14. return goodsId;
    15. }
    16. public void setGoodsId(Integer goodsId) {
    17. this.goodsId = goodsId;
    18. }
    19. public String getGdPicUrl() {
    20. return gdPicUrl;
    21. }
    22. public void setGdPicUrl(String gdPicUrl) {
    23. this.gdPicUrl = gdPicUrl;
    24. }
    25. public Integer getGdOrder() {
    26. return gdOrder;
    27. }
    28. public void setGdOrder(Integer gdOrder) {
    29. this.gdOrder = gdOrder;
    30. }
    31. }
  2. 新建mapper xml文件 GoodsDetailMapper.xml

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <!DOCTYPE mapper
    3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    5. <mapper namespace="goodsDetail">
    6. <select id="selectByGoodsId" parameterType="Integer"
    7. resultType="com.dodoke.mybatis.entity.GoodsDetail">
    8. select * from t_goods_detail where goods_id = #{value}
    9. </select>
    10. </mapper>
  3. 修改Goods类,为体现一对多的关系,新增一个属性

    1. /**
    2. * 数据库t_goods表对应映射的实体类
    3. */
    4. public class Goods {
    5. private Integer goodsId;//商品编号
    6. private String title;//标题
    7. private String subTitle;//子标题
    8. private Float originalCost;//原始价格
    9. private Float currentPrice;//当前价格
    10. private Float discount;//折扣率
    11. private Integer isFreeDelivery;//是否包邮 ,1-包邮 0-不包邮
    12. private Integer categoryId;//分类编号
    13. private List<GoodsDetail> goodsDetails;
    14. public List<GoodsDetail> getGoodsDetails() {
    15. return goodsDetails;
    16. }
    17. public void setGoodsDetails(List<GoodsDetail> goodsDetails) {
    18. this.goodsDetails = goodsDetails;
    19. }
    20. public Integer getGoodsId() {
    21. return goodsId;
    22. }
    23. public void setGoodsId(Integer goodsId) {
    24. this.goodsId = goodsId;
    25. }
    26. public String getTitle() {
    27. return title;
    28. }
    29. public void setTitle(String title) {
    30. this.title = title;
    31. }
    32. public String getSubTitle() {
    33. return subTitle;
    34. }
    35. public void setSubTitle(String subTitle) {
    36. this.subTitle = subTitle;
    37. }
    38. public Float getOriginalCost() {
    39. return originalCost;
    40. }
    41. public void setOriginalCost(Float originalCost) {
    42. this.originalCost = originalCost;
    43. }
    44. public Float getCurrentPrice() {
    45. return currentPrice;
    46. }
    47. public void setCurrentPrice(Float currentPrice) {
    48. this.currentPrice = currentPrice;
    49. }
    50. public Float getDiscount() {
    51. return discount;
    52. }
    53. public void setDiscount(Float discount) {
    54. this.discount = discount;
    55. }
    56. public Integer getIsFreeDelivery() {
    57. return isFreeDelivery;
    58. }
    59. public void setIsFreeDelivery(Integer isFreeDelivery) {
    60. this.isFreeDelivery = isFreeDelivery;
    61. }
    62. public Integer getCategoryId() {
    63. return categoryId;
    64. }
    65. public void setCategoryId(Integer categoryId) {
    66. this.categoryId = categoryId;
    67. }
    68. }
  4. 利用resultMap实现一对多映射,GoodsMapper.xml

    1. <!--
    2. resultMap可用于说明一对多或者多对一的映射逻辑
    3. id 是resultMap属性引用的标志
    4. type 指向One的实体(Goods)
    5. -->
    6. <resultMap id="rmGoods1" type="com.dodoke.mybatis.entity.Goods">
    7. <!-- 映射goods对象的主键到goods_id字段 -->
    8. <id column="goods_id" property="goodsId"></id>
    9. <!--
    10. collection的含义是,在
    11. select * from t_goods limit 0,10 得到结果后,对所有Goods对象遍历得到goods_id字段值,
    12. 并代入到goodsDetail命名空间的findByGoodsId的SQL中执行查询,
    13. 将得到的"商品详情"集合赋值给goodsDetails List对象.
    14. -->
    15. <collection property="goodsDetails" select="goodsDetail.selectByGoodsId"
    16. column="goods_id"/>
    17. </resultMap>
    18. <select id="selectOneToMany" resultMap="rmGoods1">
    19. select * from t_goods limit 0,10
    20. </select>
  5. 编写测试方法

    1. /**
    2. * 一对多对象关联查询
    3. * @throws Exception
    4. */
    5. @Test
    6. public void testOneToMany() throws Exception {
    7. SqlSession session = null;
    8. try {
    9. session = MyBatisUtils.openSqlSession();
    10. List<Goods> list = session.selectList("com.dodoke.mybatis.resources.mappers.GoodsMapper.selectOneToMany");
    11. for(Goods goods:list) {
    12. System.out.println(goods.getTitle() + ":" + goods.getGoodsDetails().size());
    13. }
    14. } catch (Exception e) {
    15. throw e;
    16. } finally {
    17. MyBatisUtils.closeSqlSession(session);
    18. }
    19. }

    多对一关联查询

    当多对一的时候,只需要在多的一方实体类中,持有一的一方的实体!
    即:

    1. package com.dodoke.mybatis.entity;
    2. public class GoodsDetail {
    3. private Integer gdId;
    4. private Integer goodsId;
    5. private String gdPicUrl;
    6. private Integer gdOrder;
    7. private Goods goods;//添加goods类属性
    8. public Integer getGdId() {
    9. return gdId;
    10. }
    11. public void setGdId(Integer gdId) {
    12. this.gdId = gdId;
    13. }
    14. public Integer getGoodsId() {
    15. return goodsId;
    16. }
    17. public void setGoodsId(Integer goodsId) {
    18. this.goodsId = goodsId;
    19. }
    20. public String getGdPicUrl() {
    21. return gdPicUrl;
    22. }
    23. public void setGdPicUrl(String gdPicUrl) {
    24. this.gdPicUrl = gdPicUrl;
    25. }
    26. public Integer getGdOrder() {
    27. return gdOrder;
    28. }
    29. public void setGdOrder(Integer gdOrder) {
    30. this.gdOrder = gdOrder;
    31. }
    32. public Goods getGoods() {
    33. return goods;
    34. }
    35. public void setGoods(Goods goods) {
    36. this.goods = goods;
    37. }
    38. }

    修改GoodsDetailMapper.xml

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <!DOCTYPE mapper
    3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    5. <mapper namespace="goodsDetail">
    6. <select id="selectByGoodsId" parameterType="Integer"
    7. resultType="com.dodoke.mybatis.entity.GoodsDetail">
    8. select * from t_goods_detail where goods_id = #{value}
    9. </select>
    10. <resultMap id="rmGoodsDetail" type="com.dodoke.mybatis.entity.GoodsDetail">
    11. <!-- 除了id,只有其它的属性符合驼峰命名规则就不需要填写大量的result标签 -->
    12. <id column="gd_id" property="gdId"/>
    13. <!-- 因为在下方使用了goods属性,导致goods_id没有对goodsId进行正确赋值,所以需要进行手动赋值 -->
    14. <result column="goods_id" property="goodsId"/>
    15. <!-- 该标签表示从多的一方关联到一的一方 -->
    16. <association property="goods" select="com.dodoke.mybatis.resources.mappers.GoodsMapper.selectById" column="goods_id"></association>
    17. </resultMap>
    18. <select id="selectManyToOne" resultMap="rmGoodsDetail">
    19. select * from t_goods_detail limit 0,20
    20. </select>
    21. </mapper>

    MyBatis整合C3P0连接池

    在之前的课程中,我们就使用过连接池。而且在mybatis-config.xml文件中也设置了使用数据库连接池,但是这个数据库连接池是使用的MyBatis自带的数据库连接池。我们希望使用更好的数据库连接池,可以采用C3P0连接池替换掉自带连接池。
    pom.xml中添加依赖

    1. <dependency>
    2. <groupId>com.mchange</groupId>
    3. <artifactId>c3p0</artifactId>
    4. <version>0.9.5.2</version>
    5. </dependency>

    新增一个C3P0DataSourceFactory扩展类

    1. package com.dodoke.mybatis.datasources;
    2. import com.mchange.v2.c3p0.ComboPooledDataSource;
    3. import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
    4. /**
    5. * C3P0与MyBatis兼容使用的数据源工厂类
    6. * 继承UnpooledDataSourceFactory类实现C3P0的迁入工作。
    7. */
    8. public class C3P0DataSourceFactory extends UnpooledDataSourceFactory {
    9. public C3P0DataSourceFactory(){
    10. //指UnpooledDataSourceFactory类的数据源由C3P0提供
    11. this.dataSource = new ComboPooledDataSource();
    12. }
    13. }

    修改mybatis-config.xml,type改成指向新增的类:C3P0DataSourceFactory
    5.MyBatis进阶 - 图4
    修改C3P0属性值

    1. <!--<dataSource type="POOLED">-->
    2. <dataSource type="com.dodoke.mybatis.datasources.C3P0DataSourceFactory">
    3. <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
    4. <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/babytun?serverTimezone=UTC&amp;characterEncoding=UTF-8"/>
    5. <property name="user" value="root"/>
    6. <property name="password" value="123456"/>
    7. <property name="initialPoolSize" value="5"/>
    8. <property name="maxPoolSize" value="20"/>
    9. <property name="minPoolSize" value="5"/>
    10. </dataSource>

    MyBatis的批量处理

    MyBatis的批量处理实际上就是通过循环实现SQL的批量执行

    1. <!--INSERT INTO table-->
    2. <!--VALUES ("a" , "a1" , "a2"),("b" , "b1" , "b2"),(....)-->
    3. <insert id="batchInsert" parameterType="java.util.List">
    4. INSERT INTO t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery, category_id)
    5. VALUES
    6. <foreach collection="list" item="item" index="index" separator=",">
    7. (#{item.title},#{item.subTitle}, #{item.originalCost}, #{item.currentPrice}, #{item.discount}, #{item.isFreeDelivery}, #{item.categoryId})
    8. </foreach>
    9. </insert>
    10. <!--in (1901,1902)-->
    11. <delete id="batchDelete" parameterType="java.util.List">
    12. DELETE FROM t_goods WHERE goods_id in
    13. <foreach collection="list" item="item" index="index" open="(" close=")" separator=",">
    14. #{item}
    15. </foreach>
    16. </delete>
  • collection=”list”代表迭代的数据源从哪来,一般情况下书写list,指代从外侧传来的List集合,这个名字是mybatis强制要求不能随意修改
  • item=”item” 循环中的迭代遍历
  • indx=”index” 循环的索引,当前是第几次循环
  • separator=”,” 分割器,生成文本时((“a”,”a1”,”a2”),(“b”,”b1”,”b2”),…),每个记录用逗号分割
  • 批量删除中传入的list中包含的是每一个要删除的数据的编号,foreach标签中要加入open=”(“ close=”)”
    1. /**
    2. * 批量插入测试
    3. * @throws Exception
    4. */
    5. @Test
    6. public void testBatchInsert() throws Exception {
    7. SqlSession session = null;
    8. try {
    9. long st = new Date().getTime();
    10. session = MyBatisUtils.openSqlSession();
    11. List list = new ArrayList();
    12. for (int i = 0; i < 10000; i++) {
    13. Goods goods = new Goods();
    14. goods.setTitle("测试商品");
    15. goods.setSubTitle("测试子标题");
    16. goods.setOriginalCost(200f);
    17. goods.setCurrentPrice(100f);
    18. goods.setDiscount(0.5f);
    19. goods.setIsFreeDelivery(1);
    20. goods.setCategoryId(43);
    21. //insert()方法返回值代表本次成功插入的记录总数
    22. list.add(goods);
    23. }
    24. session.insert("goods.batchInsert", list);
    25. session.commit();//提交事务数据
    26. long et = new Date().getTime();
    27. System.out.println("执行时间:" + (et - st) + "毫秒");
    28. // System.out.println(goods.getGoodsId());
    29. } catch (Exception e) {
    30. if (session != null) {
    31. session.rollback();//回滚事务
    32. }
    33. throw e;
    34. } finally {
    35. MyBatisUtils.closeSqlSession(session);
    36. }
    37. }
    38. /**
    39. * 10000次数据插入对比测试用例
    40. * @throws Exception
    41. */
    42. @Test
    43. public void testInsert1() throws Exception {
    44. SqlSession session = null;
    45. try{
    46. long st = new Date().getTime();
    47. session = MyBatisUtils.openSqlSession();
    48. List list = new ArrayList();
    49. for(int i = 0 ; i < 10000 ; i++) {
    50. Goods goods = new Goods();
    51. goods.setTitle("测试商品");
    52. goods.setSubTitle("测试子标题");
    53. goods.setOriginalCost(200f);
    54. goods.setCurrentPrice(100f);
    55. goods.setDiscount(0.5f);
    56. goods.setIsFreeDelivery(1);
    57. goods.setCategoryId(43);
    58. //insert()方法返回值代表本次成功插入的记录总数
    59. session.insert("goods.insert" , goods);
    60. }
    61. session.commit();//提交事务数据
    62. long et = new Date().getTime();
    63. System.out.println("执行时间:" + (et-st) + "毫秒");
    64. // System.out.println(goods.getGoodsId());
    65. }catch (Exception e){
    66. if(session != null){
    67. session.rollback();//回滚事务
    68. }
    69. throw e;
    70. }finally {
    71. MyBatisUtils.closeSqlSession(session);
    72. }
    73. }
    74. /**
    75. * 批量删除测试
    76. * @throws Exception
    77. */
    78. @Test
    79. public void testBatchDelete() throws Exception {
    80. SqlSession session = null;
    81. try {
    82. long st = new Date().getTime();
    83. session = MyBatisUtils.openSqlSession();
    84. List list = new ArrayList();
    85. list.add(1920);
    86. list.add(1921);
    87. list.add(1922);
    88. session.delete("goods.batchDelete", list);
    89. session.commit();//提交事务数据
    90. long et = new Date().getTime();
    91. System.out.println("执行时间:" + (et - st) + "毫秒");
    92. // System.out.println(goods.getGoodsId());
    93. } catch (Exception e) {
    94. if (session != null) {
    95. session.rollback();//回滚事务
    96. }
    97. throw e;
    98. } finally {
    99. MyBatisUtils.closeSqlSession(session);
    100. }
    101. }
    批量插入数据的局限,需要通过压力测试来调整
  1. 无法获得插入的数据id
  2. 批量生成的SQL太长,可能会被服务器拒绝。

    对MyBatis中使用到的类起别名

    之前,我们在 mapper xml 文件中的引用实体类时,需要写上实体类的全类名(包名+类名),每次都写这么一长串内容挺麻烦的,而我们希望能够采用一种简写的形式。比如写成这种形式就挺舒服的。
    1. <select id="selectAll" resultType="_Goods">
    2. select * from t_goods order by goods_id desc limit 10
    3. </select>
    可以在mybatis-config.xml标签中添加typeAliases,注意添加位置。
    5.MyBatis进阶 - 图5
    1. <settings>
    2. <!-- 驼峰命名转化设置 -->
    3. <!-- 该设置表示将数据库中表的字段,比如goods_id => goodsId -->
    4. <setting name="mapUnderscoreToCamelCase" value="true"/>
    5. </settings>
    6. <typeAliases>
    7. <typeAlias type="com.dodoke.mybatis.entity.Goods" alias="_Goods"/>
    8. </typeAliases>

    Mybatis使用注解进行开发

    对于Mybatis而言,它提供了一种使用注解的开发方式,这种开发方式与使用xml进行开发比较,它更适合使用在一些小型敏捷的项目中。
    5.MyBatis进阶 - 图6
    在之前的项目基础上新建一个项目:(pom.xml中依赖不变,工具类不变,logback自定义文件不变)
    5.MyBatis进阶 - 图7
    mybatis-config.xml
    1. <?xml version="1.0" encoding="utf-8" ?>
    2. <!-- 官网复制DTD约束 -->
    3. <!DOCTYPE configuration
    4. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    5. "http://mybatis.org/dtd/mybatis-3-config.dtd">
    6. <!-- 设置根节点 -->
    7. <configuration>
    8. <settings>
    9. <!-- 驼峰命名转化设置 -->
    10. <setting name="mapUnderscoreToCamelCase" value="true"/>
    11. </settings>
    12. <environments default="dev">
    13. <environment id="dev">
    14. <transactionManager type="JDBC"></transactionManager>
    15. <!-- 数据源节点,设置type="POOLED"采用数据库连接池的方式管理数据库连接 -->
    16. <dataSource type="POOLED">
    17. <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
    18. <property name="url" value="jdbc:mysql://localhost:3306/babytun?serverTimezone=UTC&amp;characterEncoding=UTF-8"/>
    19. <property name="username" value="root"/>
    20. <property name="password" value="123456"/>
    21. </dataSource>
    22. </environment>
    23. </environments>
    24. <mappers>
    25. <!-- mybatis如果使用注解开发,需要将接口当做mapper xml 进行注册-->
    26. <!--<mapper class="com.dodoke.mybatisannotation.dao.GoodsDao"/>-->
    27. <!-- 可以通过package标签将该包中接口全部注册 -->
    28. <package name="com.dodoke.mybatisannotation.dao"/>
    29. </mappers>
    30. </configuration>
    实体类
    1. public class Goods {
    2. private Integer goodsId;//商品编号
    3. private String title;//标题
    4. private String subTitle;//子标题
    5. private Float originalCost;//原始价格
    6. private Float currentPrice;//当前价格
    7. private Float discount;//折扣率
    8. private Integer isFreeDelivery;//是否包邮 ,1-包邮 0-不包邮
    9. private Integer categoryId;//分类编号
    10. public Integer getGoodsId() {
    11. return goodsId;
    12. }
    13. public void setGoodsId(Integer goodsId) {
    14. this.goodsId = goodsId;
    15. }
    16. public String getTitle() {
    17. return title;
    18. }
    19. public void setTitle(String title) {
    20. this.title = title;
    21. }
    22. public String getSubTitle() {
    23. return subTitle;
    24. }
    25. public void setSubTitle(String subTitle) {
    26. this.subTitle = subTitle;
    27. }
    28. public Float getOriginalCost() {
    29. return originalCost;
    30. }
    31. public void setOriginalCost(Float originalCost) {
    32. this.originalCost = originalCost;
    33. }
    34. public Float getCurrentPrice() {
    35. return currentPrice;
    36. }
    37. public void setCurrentPrice(Float currentPrice) {
    38. this.currentPrice = currentPrice;
    39. }
    40. public Float getDiscount() {
    41. return discount;
    42. }
    43. public void setDiscount(Float discount) {
    44. this.discount = discount;
    45. }
    46. public Integer getIsFreeDelivery() {
    47. return isFreeDelivery;
    48. }
    49. public void setIsFreeDelivery(Integer isFreeDelivery) {
    50. this.isFreeDelivery = isFreeDelivery;
    51. }
    52. public Integer getCategoryId() {
    53. return categoryId;
    54. }
    55. public void setCategoryId(Integer categoryId) {
    56. this.categoryId = categoryId;
    57. }
    58. @Override
    59. public String toString() {
    60. return "Goods{" +
    61. "goodsId=" + goodsId +
    62. ", title='" + title + '\'' +
    63. ", subTitle='" + subTitle + '\'' +
    64. ", originalCost=" + originalCost +
    65. ", currentPrice=" + currentPrice +
    66. ", discount=" + discount +
    67. ", isFreeDelivery=" + isFreeDelivery +
    68. ", categoryId=" + categoryId +
    69. '}';
    70. }
    71. }
    数据传输类
    1. package com.dodoke.mybatisannotation.dto;
    2. public class GoodsDTO {
    3. private int goodsId;
    4. private String title;
    5. private String subTitle;
    6. public int getGoodsId() {
    7. return goodsId;
    8. }
    9. public void setGoodsId(int goodsId) {
    10. this.goodsId = goodsId;
    11. }
    12. public String getTitle() {
    13. return title;
    14. }
    15. public void setTitle(String title) {
    16. this.title = title;
    17. }
    18. public String getSubTitle() {
    19. return subTitle;
    20. }
    21. public void setSubTitle(String subTitle) {
    22. this.subTitle = subTitle;
    23. }
    24. @Override
    25. public String toString() {
    26. return "GoodsDTO{" +
    27. "goodsId=" + goodsId +
    28. ", title='" + title + '\'' +
    29. ", subTitle='" + subTitle + '\'' +
    30. '}';
    31. }
    32. }
    接口注解开发-接口
    package com.dodoke.mybatisannotation.dao;
    import com.dodoke.mybatisannotation.dto.GoodsDTO;
    import com.dodoke.mybatisannotation.entity.Goods;
    import org.apache.ibatis.annotations.*;
    import java.util.List;
    import java.util.Map;
    /**
    * 该接口用操作数据库
    */
    public interface GoodsDao {
     @Select("select * from t_goods where current_price between #{min} and #{max} order by current_price limit 0,#{limt}")
     public List<Goods> selectByPriceRange(@Param("min") Float min, @Param("max") Float max, @Param("limt") Integer limt);
     /**
      * 对于注解开发来说,新增和删除,以及修改方法的返回值都要是int类型
      * @param goods
      * @return
      */
     @Insert("INSERT INTO t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery, category_id) VALUES (#{title} , #{subTitle} , #{originalCost}, #{currentPrice}, #{discount}, #{isFreeDelivery}, #{categoryId})")
     @SelectKey(statement = "select last_insert_id()" ,before=false,keyProperty = "goodsId" ,resultType = Integer.class)
     public int insert(Goods goods);
     @Select(" select * from t_goods order by goods_id desc limit 10")
     //如果没有设置驼峰命令转换或者要设置数据转换类,或者多对一,一对多的时候,可以利用results注解
     @Results({
             //设置id=true,明确指示id属性
             @Result(column = "goods_id",property = "goodsId" , id=true),
             @Result(column = "title",property = "title" ),
             @Result(column = "sub_title",property = "subTitle" ),
     })
     public List<GoodsDTO> selectLimit();
    }