17_高级映射:一对一查询(使用resultType)
【数据库模型】
【各个表】
[ 用户表user ]
购买商品的用户信息。
[ 订单表 ]
用户所创建的订单
[ 订单明细表 ]
订单的详细信息,即购买商品的信息
[ 商品表 ]
商品的具体信息
【有关系的表之间的业务关系】
分析表与表之间的业务关系时,需要建立在某个业务意义的基础之上去分析。
[ user 与 orders ]
user ---> orders :一个用户可以创建多个订单, 一对多
orders ---> user :一个订单只能由一个用户创建,一对一
[ orders与orderdetail ]
orders ---> orderdetail :一个订单可以包括多个订单明细。(一个订单可以购买多个商品,每个商品的购买信息存在orderdetail信息),一对多
orderdetail ---> orders :一个订单明细只能包含在一个订单之中,一对一
[ orderdetail 与 items]
orderdetail ---> items :一个订单明细只对应一个商品信息,一对一
items ---> orderdetail :一个商品可以包含多个订单明细,一对多
【 没关系的表之间的业务关系】
[orders 与 items]
orders 和 items 之间可以通过orderdetail表建立关系
【建表语句】
/*Table structure for table `items` */ CREATE TABLE `items` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(32) NOT NULL COMMENT '商品名称', `price` float(10,1) NOT NULL COMMENT '商品定价', `detail` text COMMENT '商品描述', `pic` varchar(64) DEFAULT NULL COMMENT '商品图片', `createtime` datetime NOT NULL COMMENT '生产日期', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; /*Table structure for table `orderdetail` */ CREATE TABLE `orderdetail` ( `id` int(11) NOT NULL AUTO_INCREMENT, `orders_id` int(11) NOT NULL COMMENT '订单id', `items_id` int(11) NOT NULL COMMENT '商品id', `items_num` int(11) DEFAULT NULL COMMENT '商品购买数量', PRIMARY KEY (`id`), KEY `FK_orderdetail_1` (`orders_id`), KEY `FK_orderdetail_2` (`items_id`), CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; /*Table structure for table `orders` */ CREATE TABLE `orders` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL COMMENT '下单用户id', `number` varchar(32) NOT NULL COMMENT '订单号', `createtime` datetime NOT NULL COMMENT '创建订单时间', `note` varchar(100) DEFAULT NULL COMMENT '备注', PRIMARY KEY (`id`), KEY `FK_orders_1` (`user_id`), CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; /*Table structure for table `user` */ CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL COMMENT '用户名称', `birthday` date DEFAULT NULL COMMENT '生日', `sex` char(1) DEFAULT NULL COMMENT '性别', `address` varchar(256) DEFAULT NULL COMMENT '地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
【插入测试数据】(先插入没有外键约束的数据)
INSERT INTO `items` VALUES (1, '台式机', 3000.0, '该电脑质量非常好!!!!', NULL, '2015-2-3 13:22:53'); INSERT INTO `items` VALUES (2, '笔记本', 6000.0, '笔记本性能好,质量好!!!!!', NULL, '2015-2-9 13:22:57'); INSERT INTO `items` VALUES (3, '背包', 200.0, '名牌背包,容量大质量好!!!!', NULL, '2015-2-6 13:23:02'); INSERT INTO `user` VALUES (1, '王五', '2016-1-5', '2', '天津'); INSERT INTO `user` VALUES (10, '张三', '2014-7-10', '1', '北京市'); INSERT INTO `user` VALUES (16, '张小明', '2016-2-9', '1', '浙江杭州'); INSERT INTO `user` VALUES (22, '陈小明', '2016-9-25', '1', '福建厦门'); INSERT INTO `user` VALUES (24, '张三丰', '2016-9-17', '1', '湖北武汉'); INSERT INTO `user` VALUES (25, '陈小明', '2016-2-17', '1', '上海'); INSERT INTO `user` VALUES (26, '王五', '2010-7-6', '2', '深圳'); INSERT INTO `orders` VALUES (3, 1, '1000010', '2016-8-16 13:22:35', NULL); INSERT INTO `orders` VALUES (4, 1, '1000011', '2016-6-23 13:22:41', NULL); INSERT INTO `orders` VALUES (5, 10, '1000012', '2016-9-22 16:13:23', NULL); INSERT INTO `orderdetail` VALUES (1, 3, 1, 1); INSERT INTO `orderdetail` VALUES (2, 3, 2, 3); INSERT INTO `orderdetail` VALUES (3, 4, 3, 4); INSERT INTO `orderdetail` VALUES (4, 4, 2, 3);
【需求】
查询订单信息,关联查询创建订单的用户信息。
【工程截图】
【Orders.java】
package cn.higgin.mybatis.po; import java.util.Date; public class Orders { private Integer id; private Integer userId; private String number; private Date createtime; private String note; //忽略get/set方法..... }
【OrdersCustom.java】创建pojo,将SQL要查询的结果全部映射到pojo中,pojo中必须包括所有查询列名。
(原始的Orders.java中不包含User中的字段,所以创建了OrdersCustom.java,继承Orders.java并且补充对应所需的User中的字段)
package cn.higgin.mybatis.po; /** * 通过此类映射订单和用户查询结果,让此类继承包括字段较多的pojo类 */ public class OrdersCustom extends Orders{ //添加用户的信息 private String username; private String sex; private String address; //忽略get/set方法...... }
【OrdersMapperCustom.java 接口】
package cn.higgin.mybatis.mapper; import java.util.List; import cn.higgin.mybatis.po.OrdersCustom; public interface OrdersMapperCustom { //查询订单关联查询用户信息 public List<OrdersCustom> findOrdersUser() throws Exception; }
【OrdersMapperCustome.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"> <mapper namespace="cn.higgin.mybatis.mapper.OrdersMapperCustom"> <select id="findOrdersUser" resultType="cn.higgin.mybatis.po.OrdersCustom"> SELECT orders.*, USER.username, USER.sex, USER.address FROM orders,USER WHERE orders.user_id=user.id </select> </mapper>
【配置文件db.properties】
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis jdbc.username=root jdbc.password=
【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 resource="db.properties"> <!-- properties中还可以配置一些属性名和属性值 --> <!-- <properties name="jdbc.driver" value=""/> --> </properties> <!-- 别名定义 --> <typeAliases> <!-- 批量别名定义 指定包名,mybatis自动扫描包中的po类,自动定义别名,别名就是类名 --> <package name="cn.higgin.mybatis.po" /> </typeAliases> <!-- 和spring整合后 environments配置将废除--> <environments default="development"> <environment id="development"> <!-- 使用jdbc事务管理,事务控制由mybatis--> <transactionManager type="JDBC" /> <!-- 数据库连接池,由mybatis管理--> <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 resource="sqlmap/User.xml"/> --> <!--通过resource方法一次加载一个映射文件 --> <!-- <mapper resource="mapper/UserMapper.xml"/> --> <!-- 通过mapper接口加载单个 映射文件 遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录 中 上边规范的前提是:使用的是mapper代理方法 --> <!-- <mapper class="cn.higgin.mybatis.mapper.UserMapper"/> --> <!-- 批量加载mapper 指定mapper接口的包名,mybatis自动扫描包下边所有mapper接口进行加载 遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录 中 上边规范的前提是:使用的是mapper代理方法 --> <package name="cn.higgin.mybatis.mapper"/> </mappers> </configuration>
【测试 OrdersMapperCustom.java】
package cn.higgin.mybatis.mapper; import java.io.InputStream; 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.higgin.mybatis.po.OrdersCustom; public class OrdersMapperCustomTest { private SqlSessionFactory sqlSessionFactory; // 此方法是在执行testFindUserById之前执行 @Before public void setUp() throws Exception { // 创建sqlSessionFactory // mybatis配置文件 String resource = "SqlMapConfig.xml"; // 得到配置文件流 InputStream inputStream = Resources.getResourceAsStream(resource); // 创建会话工厂,传入mybatis的配置文件信息 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void testFindOrdersUser() throws Exception { SqlSession sqlSession=sqlSessionFactory.openSession(); //创建代理对象 OrdersMapperCustom ordersMapperCustom=sqlSession.getMapper(OrdersMapperCustom.class); //调用mapper的方法 List<OrdersCustom> list=ordersMapperCustom.findOrdersUser(); System.out.println(list.size()); sqlSession.close(); } }
【debug运行结果】
与数据库中查询出来的结果一致,故正确。
【小结】
定义专门的Po类作为输出类型,其中定义了sql查询结构集中所需的所有字段。该方法使用较为普遍。