在路上

 找回密码
 立即注册
在路上 站点首页 学习 查看内容

Java的MyBatis框架中实现多表连接查询和查询结果分页

2016-7-29 15:41| 发布者: zhangjf| 查看: 607| 评论: 0

摘要: 实现多表联合查询 还是在david.mybatis.model包下面新建一个Website类,用来持久化数据之用,重写下相应toString()方法,方便测试程序之用。 package david.mybatis.model;import java.text.SimpleDateFormat;import ...

实现多表联合查询

还是在david.mybatis.model包下面新建一个Website类,用来持久化数据之用,重写下相应toString()方法,方便测试程序之用。

  1. package david.mybatis.model;
  2. import java.text.SimpleDateFormat;
  3. import java.util.Date;
  4. public class Website {
  5. private int id;
  6. private String name;
  7. private int visitorId;
  8. private int status;
  9. private Date createTime;
  10. private Visitor visitor;
  11. public Website() {
  12. // TODO Auto-generated constructor stub
  13. createTime = new Date();
  14. visitor = new Visitor();
  15. }
  16. public Website(String name, int visitorId) {
  17. this.name = name;
  18. this.visitorId = visitorId;
  19. visitor = new Visitor();
  20. status = 1;
  21. createTime = new Date();
  22. }
  23. public int getId() {
  24. return id;
  25. }
  26. public void setId(int id) {
  27. this.id = id;
  28. }
  29. public Visitor getVisitor() {
  30. return visitor;
  31. }
  32. public void setVisitor(Visitor visitor) {
  33. this.visitor = visitor;
  34. }
  35. public String getName() {
  36. return name;
  37. }
  38. public void setName(String name) {
  39. this.name = name;
  40. }
  41. public int getStatus() {
  42. return status;
  43. }
  44. public void setStatus(int status) {
  45. this.status = status;
  46. }
  47. public Date getCreateTime() {
  48. return createTime;
  49. }
  50. public void setCreateTime(Date createTime) {
  51. this.createTime = createTime;
  52. }
  53. public int getVisitorId() {
  54. int id = 0;
  55. if (visitor == null)
  56. id = visitorId;
  57. else
  58. id = visitor.getId();
  59. return id;
  60. }
  61. public void setVisitorId(int visitorId) {
  62. this.visitorId = visitorId;
  63. }
  64. @Override
  65. public String toString() {
  66. StringBuilder sb = new StringBuilder(String.format("Website=> {Id:%d, Name:%s, CreateTime:%s}rn", id, name,
  67. new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(createTime)));
  68. if (visitor != null)
  69. sb.append(String.format("Visitor=> %s", visitor.toString()));
  70. return sb.toString();
  71. }
  72. }
复制代码

在david.mybatis.demo下面分别新建相应的操作接口:

  1. package david.mybatis.demo;
  2. import java.util.List;
  3. import david.mybatis.model.Website;
  4. public interface IWebsiteOperation {
  5. public int add(Website website);
  6. public int delete(int id);
  7. public int update(Website website);
  8. public Website query(int id);
  9. public List<Website> getList();
  10. }
复制代码

在mapper文件夹下新建WebsiteMapper.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="david.mybatis.demo.IWebsiteOperation">
  6. <sql id="getListSql">
  7. select id,
  8. name, VisitorId, status, createTime from Website
  9. where status>0
  10. </sql>
  11. <insert id="add" parameterType="Website" useGeneratedKeys="true"
  12. keyProperty="Id">
  13. insert into Website (Name, VisitorId, Status, CreateTime)
  14. values (#{name}, #{visitorId}, #{status}, #{createTime})
  15. </insert>
  16. <delete id="delete" parameterType="int">
  17. delete from website where
  18. status>0 and id = #{id}
  19. </delete>
  20. <update id="update" parameterType="Website">
  21. update website set
  22. name=#{name} where status>0 and id=#{id}
  23. </update>
  24. <select id="query" parameterType="int" resultMap="websiteRs">
  25. select
  26. Website.id siteId, Website.name siteName, Visitor.Id visitorId,
  27. Visitor.name visitorName,
  28. Website.status siteStatus, Website.createtime
  29. siteCreateTime from Website
  30. inner join Visitor on Website.visitorid =
  31. Visitor.id where Website.status>0 and
  32. Website.id=#{id}
  33. </select>
  34. <resultMap type="Website" id="websiteRs">
  35. <id column="siteId" property="id" />
  36. <result column="siteName" property="name" />
  37. <result column="siteStatus" property="status" />
  38. <result column="siteCreateTime" property="createTime" />
  39. <association property="visitor" javaType="Visitor" resultMap="visitorRs" />
  40. </resultMap>
  41. <resultMap type="Visitor" id="visitorRs">
  42. <id column="visitorId" property="id" />
  43. <result column="visitorName" property="name" />
  44. </resultMap>
  45. <select id="getList" resultMap="websiteByVisitorIdRs">
  46. <include refid="getListSql" />
  47. </select>
  48. </mapper>
复制代码

这里今天主要说的就是那个查,现在我们想要查询网站的同时分别把相应的访问者信息一起拿出来,怎么做呢,大家可以参照配置中的query,写下联表查询的SQL,

这里主要要注意的是,Website实体与Visit的实体里面Id与Name这2个属性都是一样的,所以为了避免映射出现出错现象,把相应的查询结果列起上不一样的别名,这样绑定的时候就可以避免。

假如我像下面一样配置会得到什么呢?

  1. <select id="query" parameterType="int" resultMap="websiteRs">
  2. select
  3. Website.id, Website.name siteName, Visitor.Id,
  4. Visitor.name visitorName,
  5. Website.status siteStatus, Website.createtime
  6. siteCreateTime from Website
  7. inner join Visitor on Website.visitorid =
  8. Visitor.id where Website.status>0 and
  9. Website.id=#{id}
  10. </select>
  11. <resultMap type="Website" id="websiteRs">
  12. <id column="id" property="id" />
  13. <result column="siteName" property="name" />
  14. <result column="siteStatus" property="status" />
  15. <result column="siteCreateTime" property="createTime" />
  16. <association property="visitor" javaType="Visitor"
  17. resultMap="visitorRs" />
  18. </resultMap>
  19. <resultMap type="Visitor" id="visitorRs">
  20. <id column="id" property="id" />
  21. <result column="visitorName" property="name" />
  22. </resultMap>
复制代码

201646152922153.png (685×113)

有木有发觉,Visitor的Id也变成2了,这个其实它默认映射了Website的ID,因为SQL语句查询出来的结果2个ID都是变成2了,有人会问为什么不是4呢,因为他默认匹配第一个如果你把Website.Id与Visit.Id的位置,相互换下就会发现结果又神奇的变了

201646153012231.png (732×115)

所以需要起个别名避免这种情况,这样你就会发现真相其实只有一个就是下面的:

201646153042322.png (747×120)

大家可以看到其实多表处理resultMap的方式和单表是一致的,也无非是吧列明与Javabean属性名成对应上去,可以看到在Website的节点里面前台另外一个resultMap,他就是代表Visit实体所需要映射的实体,可以使用以下方式进行关联

  1. <association property="visitor" javaType="Visitor" resultMap="visitorRs" />
复制代码

其中的visitor就是Website实体中的visit字段名,必须保证名称一致,否则就会抛出There is no getter for property named 'XXX' in 'class david.mybatis.model.Website'的异常,这在上几章已经讲述了,当然如果你觉得不用嵌套resultMap也行,嵌套也是出于其他地方可以还要用到这个配置那就提炼出来的过程,也是抽象出来的一种思想。具体使用中的ID与Result可以从官网查找相应区别说明:http://mybatis.github.io/mybatis-3/sqlmap-xml.html#Result_Maps

这样,一个简单的多表联合查询就出来啦~,如果还有更加复杂的查询业务费是在这个基础上些许的变通修改。

分页效果逻辑
下面要讲的是关于一个业务问题中我们常碰到的分页问题。在开发web项目的时候我们经常会使用到列表显示,一般我们都会用一些常用的列表控件例如,datatables(个人感觉十分不错),easy ui下面的那些封装好的表格控件。

  思路:在这些控件里要达到分页的效果,一般都会传2个参数,第一个是表示当前页的索引(一般从0开始),第二个表示当前页展示多少条业务记录,然后将相应的参数传递给List getList(PagenateArgs args)方法,最终实现数据库中的分页时候我们可以使用limit关键词(针对mysql)进行分页,如果是oracle或者sql server他们都有自带的rownum函数可以使用。

  针对上述思路,首先我们需要还是一如既往的在demo.mybatis.model下面新建一个名为PagenateArgs的分页参数实体类与一个名为SortDirectionEnum的枚举类,里面包含当前页面索引pageIndex, 当前页展示业务记录数pageSize, pageStart属性表示从第几条开始,(pageStart=pageIndex*pageSize)因为limit关键词用法是表示【limit 起始条数(不包含),取几条】,orderFieldStr排序字段,orderDirectionStr 排序方向,所以具体创建如下:
package david.mybatis.model;

  1. /*
  2. * 分页参数实体类
  3. */
  4. public class PagenateArgs {
  5. private int pageIndex;
  6. private int pageSize;
  7. private int pageStart;
  8. private String orderFieldStr;
  9. private String orderDirectionStr;
  10. public PagenateArgs() {
  11. // TODO Auto-generated constructor stub
  12. }
  13. public PagenateArgs(int pageIndex, int pageSize, String orderFieldStr, String orderDirectionStr) {
  14. this.pageIndex = pageIndex;
  15. this.pageSize = pageSize;
  16. this.orderFieldStr = orderFieldStr;
  17. this.orderDirectionStr = orderDirectionStr;
  18. pageStart = pageIndex * pageSize;
  19. }
  20. public int getPageIndex() {
  21. return pageIndex;
  22. }
  23. public int getPageStart() {
  24. return pageStart;
  25. }
  26. public int getPageSize() {
  27. return pageSize;
  28. }
  29. public String orderFieldStr() {
  30. return orderFieldStr;
  31. }
  32. public String getOrderDirectionStr() {
  33. return orderDirectionStr;
  34. }
  35. }
  36. package david.mybatis.model;
  37. /*
  38. * 排序枚举
  39. */
  40. public enum SortDirectionEnum {
  41. /*
  42. * 升序
  43. */
  44. ASC,
  45. /*
  46. * 降序
  47. */
  48. DESC
  49. }
复制代码

  完成上面的步骤以后我们在IVisitorOperation接口类中继续添加一个方法public List getListByPagenate(PagenateArgs args),前几章中我们其实已经有getList方法了,这次的分页其实也就是在这个的基础上稍加改动即可,IVisitorOperation接口类改动后如下所示:

  1. package david.mybatis.demo;
  2. import java.util.List;
  3. import david.mybatis.model.PagenateArgs;
  4. import david.mybatis.model.Visitor;
  5. import david.mybatis.model.VisitorWithRn;
  6. public interface IVisitorOperation {
  7. /*
  8. * 基础查询
  9. */
  10. public Visitor basicQuery(int id);
  11. /*
  12. * 添加访问者
  13. */
  14. public int add(Visitor visitor);
  15. /*
  16. * 删除访问者
  17. */
  18. public int delete(int id);
  19. /*
  20. * 更新访问者
  21. */
  22. public int update(Visitor visitor);
  23. /*
  24. * 查询访问者
  25. */
  26. public Visitor query(int id);
  27. /*
  28. * 查询List
  29. */
  30. public List<Visitor> getList();
  31. /*
  32. * 分页查询List
  33. */
  34. public List<Visitor> getListByPagenate(PagenateArgs args);
  35. }
复制代码

  接下来我们就要开始动手改动我们的VisitorMapper.xml配置文件了,新增一个节点与脚本,此处唯一的不同就是需要改下sql脚本,如下:

  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="david.mybatis.demo.IVisitorOperation">
  6. <!-- useGeneratedKeys="true"代表是否使用自增长序列, keyProperty="Id"指定自增长列是哪一列, parameterType="Visitor"指定IVisitorOperation接口类中定义中所传的相应类型 -->
  7. <insert id="add" parameterType="Visitor" useGeneratedKeys="true"
  8. keyProperty="Id">
  9. insert into Visitor (Name, Email, Status, CreateTime)
  10. values (#{name}, #{email}, #{status}, #{createTime})
  11. </insert>
  12. <delete id="delete" parameterType="int">
  13. delete from Visitor where
  14. status>0 and id = #{id}
  15. </delete>
  16. <update id="update" parameterType="Visitor">
  17. update Visitor set Name =
  18. #{name}, Email=#{email}, Status=#{status} where id=#{id} and Status>0;
  19. </update>
  20. <select id="query" parameterType="int" resultType="Visitor">
  21. select Id,
  22. Name, Email, Status, CreateTime from visitor where id=#{id} and
  23. Status>0 order by Id
  24. </select>
  25. <select id="basicQuery" parameterType="int" resultType="Visitor">
  26. select *
  27. from visitor where id=#{id} and
  28. Status>0 order by Id
  29. </select>
  30. <select id="getList" resultMap="visitorRs">
  31. <include refid="getListSql" />
  32. </select>
  33. <sql id="getListSql">
  34. select * from Visitor where
  35. status>0
  36. </sql>
  37. <resultMap type="Visitor" id="visitorRs">
  38. <id column="Id" property="id" />
  39. <result column="Name" property="name" />
  40. <result column="Email" property="email" />
  41. <result column="Status" property="status" />
  42. <result column="CreateTime" property="createTime" />
  43. </resultMap>
  44. <select id="getListByPagenate" parameterType="PagenateArgs"
  45. resultType="Visitor">
  46. select * from (
  47. <include refid="getListSql" /> <include refid="orderBySql"/>
  48. ) t <!-- #{}表示参数化输出,${}表示直接输出不进行任何转义操作,自己进行转移 -->
  49. <if test="pageStart>-1 and pageSize>-1">
  50. limit #{pageStart}, #{pageSize}
  51. </if>
  52. </select>
  53. <!--提炼出来为了2个示例共用下 -->
  54. <sql id="orderBySql">
  55. order by ${orderFieldStr} ${orderDirectionStr}
  56. </sql>
  57. <!-- 带rownum的SQL脚本书写方式 -->
  58. <resultMap type="VisitorWithRn" id="visitorWithRnRs">
  59. <id column="Id" property="id" />
  60. <result column="Name" property="name" />
  61. <result column="Email" property="email" />
  62. <result column="Status" property="status" />
  63. <result column="CreateTime" property="createTime" />
  64. <result column="Rownum" property="rownum" />
  65. </resultMap>
  66. <select id="getListByPagenateWithRn" resultMap="visitorWithRnRs">
  67. <!-- #{}表示参数化输出,${}表示直接输出不进行任何转义操作,自己进行转移 -->
  68. select t.Rownum, t.Id, t.Name, t.Email, t.Status, t.CreateTime from (<include refid="getListSqlContainsRn" /> <include refid="orderBySql"/>) t
  69. <if test="pageStart>-1 and pageSize>-1">
  70. limit #{pageStart}, #{pageSize}
  71. </if>
  72. </select>
  73. <sql id="getListSqlContainsRn">
  74. select @rownum:=@rownum+1 Rownum,
  75. result.id, result.name, result.email, result.status, result.createTime
  76. FROM (
  77. select @rownum:=0, Visitor.* from Visitor where
  78. status>0) result
  79. </sql>
  80. </mapper>
复制代码

接下来剩下的就是如刚才在DemoRun下面添加测试方法,这里就不贴图了,完成后你可以看到刚刚的6-10条数据会变成如下

201646153839223.png (620×298)

最新评论

小黑屋|在路上 ( 蜀ICP备15035742号-1 

;

GMT+8, 2025-5-6 10:22

Copyright 2015-2025 djqfx

返回顶部