您好,登錄后才能下訂單哦!
這篇“MyBatis怎么實現(xiàn)多表聯(lián)合查詢及優(yōu)化”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“MyBatis怎么實現(xiàn)多表聯(lián)合查詢及優(yōu)化”文章吧。
老規(guī)矩,開始之前,還是要先說說這件事的背景。也就是最近幾天,公司要做一個后臺的管理平臺,由于之前的一些限制,這次要做成單獨的項目進行部署,因此就要重新考慮很多東西。索性這幾天有時間,就做了一個小 Demo ,實現(xiàn) mybatis 的多表聯(lián)合查詢的,由于之前用的是 Hibernate 做的聯(lián)合查詢,眾所周知,Hibernate 是全自動的數(shù)據(jù)庫持久層框架,它可以通過實體來映射數(shù)據(jù)庫,通過設(shè)置一對多、多對一、一對一、多對多的關(guān)聯(lián)來實現(xiàn)聯(lián)合查詢。
下面就來說一下 mybatis 是通過什么來實現(xiàn)多表聯(lián)合查詢的。首先看一下表關(guān)系,如圖:
這里,我已經(jīng)搭好了開發(fā)的環(huán)境,用到的是 SpringMVC + Spring + MyBatis,當(dāng)然,為了簡單期間,你可以不用搭前端的框架,只使用 Spring + MyBatis 就可以,外加 junit 測試即可。環(huán)境我就不帶大家搭了,這里只說涉及到聯(lián)合查詢的操作。
設(shè)計好表之后,我用到了 mybatis 的自動生成工具 mybatis generator 生成的實體類、mapper 接口、以及 mapper xml 文件。由于是測試多表聯(lián)合查詢,因此需要自己稍加改動。
下面是 User 和 Role 的實體類代碼:
User
<span >package com.sica.domain; import java.io.Serializable; import java.util.List; public class User implements Serializable { private String id; private String username; private String password; private List<Role> roles; private static final long serialVersionUID = 1L; public String getId() { return id; } public void setId(String id) { this.id = id == null ? null : id.trim(); } public String getUsername() { return username; } public void setUsername(String username) { this.username = username == null ? null : username.trim(); } public String getPassword() { return password; } public void setPassword(String password) { this.password = password == null ? null : password.trim(); } public List<Role> getRoles() { return roles; } public void setRoles(List<Role> roles) { this.roles = roles; } @Override public boolean equals(Object that) { if (this == that) { return true; } if (that == null) { return false; } if (getClass() != that.getClass()) { return false; } User other = (User) that; return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId())) && (this.getUsername() == null ? other.getUsername() == null : this.getUsername().equals(other.getUsername())) && (this.getPassword() == null ? other.getPassword() == null : this.getPassword().equals(other.getPassword())); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((getId() == null) ? 0 : getId().hashCode()); result = prime * result + ((getUsername() == null) ? 0 : getUsername().hashCode()); result = prime * result + ((getPassword() == null) ? 0 : getPassword().hashCode()); return result; } }</span>
Role
<span >package com.sica.domain; import java.io.Serializable; public class Role implements Serializable { private String id; private String name; private String jsms; private String bz; private Integer jlzt; private String glbm; private String userid; private static final long serialVersionUID = 1L; public String getId() { return id; } public void setId(String id) { this.id = id == null ? null : id.trim(); } public String getName() { return name; } public void setName(String name) { this.name = name == null ? null : name.trim(); } public String getJsms() { return jsms; } public void setJsms(String jsms) { this.jsms = jsms == null ? null : jsms.trim(); } public String getBz() { return bz; } public void setBz(String bz) { this.bz = bz == null ? null : bz.trim(); } public Integer getJlzt() { return jlzt; } public void setJlzt(Integer jlzt) { this.jlzt = jlzt; } public String getGlbm() { return glbm; } public void setGlbm(String glbm) { this.glbm = glbm == null ? null : glbm.trim(); } public String getUserid() { return userid; } public void setUserid(String userid) { this.userid = userid == null ? null : userid.trim(); } @Override public boolean equals(Object that) { if (this == that) { return true; } if (that == null) { return false; } if (getClass() != that.getClass()) { return false; } Role other = (Role) that; return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId())) && (this.getName() == null ? other.getName() == null : this.getName().equals(other.getName())) && (this.getJsms() == null ? other.getJsms() == null : this.getJsms().equals(other.getJsms())) && (this.getBz() == null ? other.getBz() == null : this.getBz().equals(other.getBz())) && (this.getJlzt() == null ? other.getJlzt() == null : this.getJlzt().equals(other.getJlzt())) && (this.getGlbm() == null ? other.getGlbm() == null : this.getGlbm().equals(other.getGlbm())) && (this.getUserid() == null ? other.getUserid() == null : this.getUserid().equals(other.getUserid())); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((getId() == null) ? 0 : getId().hashCode()); result = prime * result + ((getName() == null) ? 0 : getName().hashCode()); result = prime * result + ((getJsms() == null) ? 0 : getJsms().hashCode()); result = prime * result + ((getBz() == null) ? 0 : getBz().hashCode()); result = prime * result + ((getJlzt() == null) ? 0 : getJlzt().hashCode()); result = prime * result + ((getGlbm() == null) ? 0 : getGlbm().hashCode()); result = prime * result + ((getUserid() == null) ? 0 : getUserid().hashCode()); return result; } }</span>
首先講一下業(yè)務(wù),這里用到的 User 、Role 的對應(yīng)關(guān)系是,一個用戶有多個角色,也就是 User : Role 是 1 : n 的關(guān)系。因此,在 User 的實體中加入一個 Role 的屬性,對應(yīng)一對多的關(guān)系。
然后就是 mapper 接口和 xml 文件了:
mapper接口
UserMapper
<span >package com.sica.mapper; import com.sica.domain.User; import java.util.List; public interface UserMapper { int deleteByPrimaryKey(String id); int insert(User record); int insertSelective(User record); User selectByPrimaryKey(String id); int updateByPrimaryKeySelective(User record); int updateByPrimaryKey(User record); List<User> queryForList(); }</span>
mapper xml文件
UserMapper
<span ><?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.sica.mapper.UserMapper"> <resultMap id="BaseResultMap" type="com.sica.domain.User"> <id column="id" property="id" jdbcType="VARCHAR"/> <result column="username" property="username" jdbcType="VARCHAR"/> <result column="password" property="password" jdbcType="VARCHAR"/> </resultMap> <resultMap id="queryForListMap" type="com.sica.domain.User"> <id column="id" property="id" jdbcType="VARCHAR"/> <result column="username" property="username" jdbcType="VARCHAR"/> <result column="password" property="password" jdbcType="VARCHAR"/> <collection property="roles" javaType="java.util.List" ofType="com.sica.domain.Role"> <id column="r_id" property="id" jdbcType="VARCHAR" /> <result column="r_name" property="name" jdbcType="VARCHAR" /> <result column="r_jsms" property="jsms" jdbcType="VARCHAR" /> <result column="r_bz" property="bz" jdbcType="VARCHAR" /> <result column="r_jlzt" property="jlzt" jdbcType="INTEGER" /> <result column="r_glbm" property="glbm" jdbcType="VARCHAR" /> </collection> </resultMap> <select id="queryForList" resultMap="queryForListMap"> SELECT u.id, u.username, u.password, r.id r_id, r.name r_name, r.jsms r_jsms, r.bz r_bz, r.jlzt r_jlzt, r.glbm r_glbm FROM user u LEFT JOIN role r ON u.id = r.userid </select> <sql id="Base_Column_List"> id, username, password </sql> <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String"> select <include refid="Base_Column_List"/> from user where id = #{id,jdbcType=VARCHAR} </select> <delete id="deleteByPrimaryKey" parameterType="java.lang.String"> delete from user where id = #{id,jdbcType=VARCHAR} </delete> <insert id="insert" parameterType="com.sica.domain.User"> insert into user (id, username, password ) values (#{id,jdbcType=VARCHAR}, #{username,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR} ) </insert> <insert id="insertSelective" parameterType="com.sica.domain.User"> insert into user <trim prefix="(" suffix=")" suffixOverrides=","> <if test="id != null"> id, </if> <if test="username != null"> username, </if> <if test="password != null"> password, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="id != null"> #{id,jdbcType=VARCHAR}, </if> <if test="username != null"> #{username,jdbcType=VARCHAR}, </if> <if test="password != null"> #{password,jdbcType=VARCHAR}, </if> </trim> </insert> <update id="updateByPrimaryKeySelective" parameterType="com.sica.domain.User"> update user <set> <if test="username != null"> username = #{username,jdbcType=VARCHAR}, </if> <if test="password != null"> password = #{password,jdbcType=VARCHAR}, </if> </set> where id = #{id,jdbcType=VARCHAR} </update> <update id="updateByPrimaryKey" parameterType="com.sica.domain.User"> update user set username = #{username,jdbcType=VARCHAR}, password = #{password,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR} </update> </mapper></span>
之后,我擴展了一個 Dao 接口,當(dāng)然,你也可以直接使用 mapper 接口,都是一樣的。
Dao 接口
IUserDao
<span >package com.sica.dao; import com.sica.mapper.UserMapper; /** * Created by IntelliJ IDEA. * Package: com.sica.dao * Name: IUserDao * User: xiang.li * Date: 2015/5/22 * Time: 15:25 * Desc: To change this template use File | Settings | File Templates. */ public interface IUserDao extends UserMapper { }</span>
下面就是 service 和實現(xiàn)層的代碼了。
IUserService
<span >package com.sica.service; import com.sica.domain.User; import java.util.List; /** * Created by xiang.li on 2015/1/31. */ public interface IUserService { /** * 根據(jù)Id查詢用戶對象 * @param id 編號 * @return 用戶對象 */ User getUserById(String id); /** * 根據(jù)用戶名查詢用戶對象 * @return List */ List<User> queryUserList(); }</span>
UserServiceImpl
<span >package com.sica.service.impl; import com.sica.dao.IUserDao; import com.sica.domain.User; import com.sica.service.IUserService; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; /** * Created by xiang.li on 2015/1/31. */ @Service("userService") public class UserServiceImpl implements IUserService { @Resource public IUserDao userDao; @Override public User getUserById(String id) { return this.userDao.selectByPrimaryKey(id); } @Override public List<User> queryUserList() { return userDao.queryForList(); } }</span>
當(dāng)然,還有所謂的 applicationContext.xml 配置,不過,我這里叫 spring-mybatis.xml。
<span ><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 自動掃描 --> <context:component-scan base-package="com.sica"/> <!-- 引入配置文件 --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:location="classpath:jdbc.properties" /> <!-- 配置數(shù)據(jù)庫連接池 --> <!-- 初始化連接大小 --> <!-- 連接池最大數(shù)量 --> <!-- 連接池最大空閑 --> <!-- 連接池最小空閑 --> <!-- 獲取連接最大等待時間 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driver}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}" p:initialSize="${jdbc.initialSize}" p:maxActive="${jdbc.maxActive}" p:maxIdle="${jdbc.maxIdle}" p:minIdle="${jdbc.minIdle}" p:maxWait="${jdbc.maxWait}" /> <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" lazy-init="default" p:dataSource-ref="dataSource" p:mapperLocations="classpath:com/sica/mapping/*.xml" /> <!-- DAO接口所在包名,Spring會自動查找其下的類 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" p:basePackage="com.sica.dao" p:sqlSessionFactoryBeanName="sqlSessionFactory" /> <!-- (事務(wù)管理)transaction manager, use JtaTransactionManager for global tx --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource" /> </beans></span>
最后,我用到的是 junit 進行的測試,測試代碼如下。
GetUserTest
<span >package com.sica.user; import com.alibaba.fastjson.JSON; import com.sica.domain.User; import com.sica.service.IUserService; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; import java.util.List; /** * Created by xiang.li on 2015/2/1. */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:spring-mybatis.xml") public class GetUserTest { private static String UUID = "3"; @Resource private IUserService userService; private static Logger logger = LoggerFactory.getLogger(GetUserTest.class); @Test public void test() { User user = userService.getUserById(UUID); logger.info(JSON.toJSONString(user)); } /** * 測試聯(lián)合查詢 */ @Test public void test2() { List<User> users = userService.queryUserList(); logger.info(JSON.toJSONString(users)); } }</span>
測試結(jié)果
可以看到,所有的用戶和用戶對應(yīng)的角色都全部查出來了,這說明,這次的測試很成功。
對于優(yōu)化嘛,我這里簡單的提幾點,大家可以考慮一下。首先,就是對表的設(shè)計,在設(shè)計表初期,不僅僅要考慮到數(shù)據(jù)庫的規(guī)范性,還好考慮到所謂的業(yè)務(wù),以及對性能的影響,比如,如果從規(guī)范性角度考慮的話,可能就會分多個表,但是如果從性能角度來考慮的話,龐大的數(shù)據(jù)量在多表聯(lián)合查詢的時候,相對于單表來說,就會慢很多,這時,如果字段不是很多的話,可以考慮冗余幾個字段采用單表的設(shè)計。
其次嘛,就是在 sql 上下功夫了,對于聯(lián)合查詢,sql 的優(yōu)化是很有必要的,到底是采用 INNER JOIN,還是采用 LEFT JOIN 亦或是 RIGHT JOIN 、OUTTER JOIN 等,都是要在滿足業(yè)務(wù)需求之后,通過測試性能得出的結(jié)論。
再次嘛,就是在程序中調(diào)用的時候了,是采用懶加載,還是采用非懶加載的方式,這也算是一個因素吧,具體的還是要考慮業(yè)務(wù)的需要。
以上就是關(guān)于“MyBatis怎么實現(xiàn)多表聯(lián)合查詢及優(yōu)化”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。