一對一查詢
需求:
查詢訂單信息,關聯查詢創建訂單的用戶信息。
記住:用Mybatis開發的順序就是
1.寫sql語句
2.創建pojo類來完成映射
3.寫Mapper.xml
4.寫Mapper.java接口
---------------------------------------------------------------------------------------------------------------------------------------------------
我們知道Mybatis中mapper.xml中分為resultType和resultMap兩種,這兩種我們都講:
一:先講resultMap:
先給出案例結構:
cn.itcast.mybatis.po包下面的類(items,orderdetail,Orders,User)都是根據數據庫的4張表創建的實體類。
1.我們先來分析一下怎麽寫sql語句:
寫sql語句時要先根據需求確定查詢的主表和查詢的關聯表:
根據“查詢訂單信息,關聯查詢創建訂單的用戶信息” 很明顯,查詢的主表是訂單表,查詢的關聯是用戶表。
關聯查詢使用內鏈接?還是外鏈接?由於orders表中有一個外鍵(user_id),通過外鍵關聯查詢用戶表只能查詢出一條記錄,可以使用內鏈接。
sql如下:
SELECT
orders.*,
USER.username,
USER.sex,
USER.address
FROM
orders,
USER
WHERE orders.user_id = user.id
2.根據select(orders.*,USER.username,USER.sex,USER.address)語句 創建Pojo類
我們創建的pojo類要滿足orders.*,USER.username,USER.sex,USER.address這些映射,很明顯單純依靠數據庫的映射(Orders.java和User.java)不能滿足,所以要新寫一個類OrdersCustom.java。
如下:
package cn.itcast.mybatis.po; import java.util.Date; public class OrdersCustom extends Orders{ private String username; private String sex; private String address; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
為什麽這個類要繼承Orders而不是繼承User.java因為根據orders.*,USER.username,USER.sex,USER.address,很明顯,要映射的數據是order表中的全部數據以及user
表中的username,sex,address這些數據,直接繼承Order類的話就可以少定義一些屬性,只要定義username,sex,address。就可以了。
3.寫Mapper.xml和Mapper.java接口(放在同一個包下面,用接口的方式去加載)
OrderMapperCustom.xml的代碼如下:
<?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"> <!-- nanmespace:命名空間。 作用就是對sql進行分類話管理,理解Sal分離 註意:使用mapper代理方式,namespace有特殊重要的作用 --> <mapper namespace="cn.itcast.mybatis.mapper.OrdersMapperCustom"> <select id="findOrdersUser" resultType="cn.itcast.mybatis.po.OrdersCustom"> SELECT ORDERS.* , user.`username`, user.`sex`, user.`address` FROM orderS,USER WHERE ORDERS.`user_id`=USER.`id` </select> </mapper>
OrdersMapperCustom.java代碼如下:
package cn.itcast.mybatis.mapper; import java.util.List; import cn.itcast.mybatis.po.OrdersCustom; public interface OrdersMapperCustom { public List<OrdersCustom> findOrdersUser(); }
同時不要忘了在SqlMapConfig.xml。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- properties的配置必須寫在typeAliases的上面 --> <properties resource="db.properties"></properties> <!-- 和spring整合後 environments配置將廢除--> <environments default="development"> <environment id="development"> <!-- 使用jdbc事務管理--> <transactionManager type="JDBC" /> <!-- 數據庫連接池--> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> <mappers> <!-- 用mapper接口的方式加載--> <!-- 遵循一些規範:需要將mapper接口類名和mapper.xml映射文件名稱保持一致 且在一個目錄中。 當著這個規範的前提是:使用mapper代理方法。 --> <mapper class="cn.itcast.mybatis.mapper.OrdersMapperCustom"/> </mappers> </configuration>
4.編寫測試代碼Mybatis_mappertest.java:
package cn.itcast.mybatis.test; import java.io.IOException; import java.io.InputStream; import java.util.Date; import java.util.List; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Before; import org.junit.Test; import cn.itcast.mybatis.mapper.OrdersMapperCustom; import cn.itcast.mybatis.mapper.userMapper; import cn.itcast.mybatis.po.User; import cn.itcast.mybatis.po.UserCustom; import cn.itcast.mybatis.po.UserQueryVo; public class Mybatis_mappertest { private SqlSessionFactory sqlSessionFactory; @Before public void setup() throws IOException { String resource="SqlMapConfig.xml"; InputStream inputStream= Resources.getResourceAsStream(resource); //主要是生成SqlsessionFactory。 this.sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream); } @Test public void testMaper() { SqlSession sqlSession=null; sqlSession=sqlSessionFactory.openSession(); //生成代理類 OrdersMapperCustom orderMapper=sqlSession.getMapper(OrdersMapperCustom.class); orderMapper.findOrdersUser(); } }
運行結果:一切正常。
二:再講resultMap(重點):
resultMap映射的思想:
使用resultMap將查詢結果中的訂單信息映射到Orders對象中,在orders類中添加User屬性,將關聯查詢出來的用戶信息映射到orders對象中的user屬性中。也就是說查出來的user信息都要映射在orders中新開的一個user屬性中。
還是按照第一sql語句,第二pojo類,第三mapper.xml,mapper.java接口這種順序來寫。
1.sql語句:和之前的resulrType的sql語句一樣:
SELECT
orders.*,
USER.username,
USER.sex,
USER.address
FROM
orders,
USER
WHERE orders.user_id = user.id
2.寫pojo類:在原來的Orders.java中新增一個User屬性:
User類:
package cn.itcast.mybatis.po; import java.util.Date; //對應數據庫中的user表 public class User { private int id;//對應數據庫中主鍵 private String username;//對應數據庫中用戶的名稱 private Date birthday;//對應數據庫中的生日 private String sex;//性別 private String address;//地址 public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
Orders.java類:
package cn.itcast.mybatis.po; import java.util.Date; public class Orders { private Integer id; private Integer user_id; private String number; private Date createtime; private String note; //新增了一個User屬性,為了保存查詢得到的關聯的User表的信息 private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getUser_id() { return user_id; } public void setUser_id(Integer user_id) { this.user_id = user_id; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public Date getCreatetime() { return createtime; } public void setCreatetime(Date createtime) { this.createtime = createtime; } public String getNote() { return note; } public void setNote(String note) { this.note = note; } }
3.寫mapper.xml和mapper.java接口
OrdersMapperCustom.xml:
<?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"> <!-- nanmespace:命名空間。 作用就是對sql進行分類話管理,理解Sal分離 註意:使用mapper代理方式,namespace有特殊重要的作用 --> <mapper namespace="cn.itcast.mybatis.mapper.OrdersMapperCustom"> <!-- 配置映射的訂單信息 --> <!-- id:指定查詢列中的唯 一標識,訂單信息的中的唯 一標識,如果有多個列組成唯一標識,配置多個id 就是說id要能唯一的標識出數據庫中的Order表。 column:訂單信息的唯 一標識 列 property:訂單信息的唯 一標識 列所映射到Orders中哪個屬性 --> <resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserResultMap"> <!-- 這一行的作用是要能唯一的識別出order表的,那麽很明顯是主鍵id --> <id column="id" property="id"/> <!-- 以下的幾行result column就是表中的字段 property就是對應到相應pojo類中的屬性--> <result column="user_id" property="user_id"/> <result column="number" property="number"/> <result column="createtime" property="createtime"/> <result column="note" property="note"/> <!-- 配置映射的關聯的用戶信息 --> <!-- association:用於映射關聯查詢單個對象的信息 property:要將關聯查詢的用戶信息映射到Orders中哪個屬性 --> <!-- 下面的代碼比較特殊,因為Order表是直接關聯到user表,下面這麽寫的目的是把user表映射到Order類中 <association property="user"這裏的user指的是orders類中的user,對應的是cn.itcast.mybatis.po.User --> <association property="user" javaType="cn.itcast.mybatis.po.User"> <!-- <id column="user_id" property="id"/>這裏的是user_id指的是order表中只有這個屬性能表示唯一的user表 --> <id column="user_id" property="id"/> <!-- 接下來的result property什麽的都是為了把user表中的字段能匹配到 cn.itcast.mybatis.po.User這個類的屬性中 --> <result column="username" property="username"/> <result column="sex" property="sex"/> <result column="address" property="address"/> </association> </resultMap> <select id="findOrdersUser" resultType="cn.itcast.mybatis.po.OrdersCustom"> SELECT ORDERS.* , user.`username`, user.`sex`, user.`address` FROM orderS,USER WHERE ORDERS.`user_id`=USER.`id` </select> <select id="findOrdersUseResultMap" resultMap="OrdersUserResultMap"> SELECT ORDERS.* , user.`username`, user.`sex`, user.`address` FROM orderS,USER WHERE ORDERS.`user_id`=USER.`id` </select> </mapper>
OrdersMapperCustom.java接口
package cn.itcast.mybatis.mapper; import java.util.List; import cn.itcast.mybatis.po.Orders; import cn.itcast.mybatis.po.OrdersCustom; public interface OrdersMapperCustom { //這裏的的函數名字要和OrdersMapperCustom.xml中的id一模一樣 public List<OrdersCustom> findOrdersUser(); public List<Orders> findOrdersUseResultMap(); }
Junit測試代碼:
package cn.itcast.mybatis.test; import java.io.IOException; import java.io.InputStream; import java.util.Date; import java.util.List; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Before; import org.junit.Test; import cn.itcast.mybatis.mapper.OrdersMapperCustom; import cn.itcast.mybatis.mapper.userMapper; import cn.itcast.mybatis.po.Orders; import cn.itcast.mybatis.po.User; import cn.itcast.mybatis.po.UserCustom; import cn.itcast.mybatis.po.UserQueryVo; public class Mybatis_mappertest { private SqlSessionFactory sqlSessionFactory; @Before public void setup() throws IOException { String resource="SqlMapConfig.xml"; InputStream inputStream= Resources.getResourceAsStream(resource); //主要是生成SqlsessionFactory。 this.sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream); } @Test public void testMaper() { SqlSession sqlSession=null; sqlSession=sqlSessionFactory.openSession(); //生成代理類 OrdersMapperCustom orderMapper=sqlSession.getMapper(OrdersMapperCustom.class); //創建包裝對象,設置查詢條件 //orderMapper.findOrdersUser(); @SuppressWarnings("unused") List<Orders>list=orderMapper.findOrdersUseResultMap(); } }
運行結果:一切正常。
resultType和resultMap實現一對一查詢小結
實現一對一查詢:
resultType:使用resultType實現較為簡單,如果pojo中沒有包括查詢出來的列名,需要增加列名對應的屬性,即可完成映射。
如果沒有查詢結果的特殊要求建議使用resultType。
resultMap:需要單獨定義resultMap,實現有點麻煩,如果對查詢結果有特殊的要求,使用resultMap可以完成將關聯查詢映射pojo的屬性中。
resultMap可以實現延遲加載,resultType無法實現延遲加載。
一對一查詢