JavaWeb框架学习文章索引
下面将以一个例子来进行演示
简单的数据模型如下:
实际sql:
/*
SQLyog v10.2
MySQL - 5.1.72-community : Database - mybatis
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*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;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
一对一查询使用resultType方式:
例1,查询订单信息和关联的用户的姓名,性别
sql语句:
select orders.*,user.username,user.sex from user,orders where user.id = orders.user_id
创建和表对用的pojo,User和Orders
由于要使用resultType方式,返回值只能指定一个pojo类型。由于orders查询出的字段更加多,所以创建一个Orders的包装类OrdersCustom并添加需要的User部分属性
代码如下:
public class OrdersCustom extends Orders{
//在查询user和orders的时候,orders的字段内容多一些,所以将user的部分属性定义到该类中
private String username;
private String sex;
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;
}
}
编写Mapper.xml:
<select id="findOrdersUser" resultType="com.hhh.dao.OrdersCustom">
select orders.*,user.username,user.sex from user,orders where user.id = orders.user_id
</select>
编写Mapper.java
public List<OrdersCustom> findOrdersUser() throws Exception;
测试方法:
@Test
public void test() throws Exception{
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();
Mapper mapper = session.getMapper(Mapper.class);
List<OrdersCustom> list = mapper.findOrdersUser();
System.out.println(list.toString());
}
dubug结果:
一对一查询使用resultMap方式:
编写xml:
<resultMap type="com.hhh.dao.Orders" id="orderUserMap">
<!-- column中的id 表示查询列中的唯一标识
加入该标识由多个字段组成,则需要配置多个id
property中的id是Orders的属性id
-->
<id column="id" property="id"/>
<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中哪个属性 -->
<association property="user" javaType="com.hhh.dao.User">
<!-- id:关联查询用户的唯一标识
column:查询列中能唯一标识用户信息的列
-->
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<result column="address" property="address"/>
</association>
</resultMap>
<select id="findOrdersUser2" resultMap="orderUserMap">
select orders.*,user.username,user.sex from user,orders where user.id = orders.user_id
</select>
方法:
public List<Orders> findOrdersUser2() throws Exception;
测试:
List<Orders> list = mapper.findOrdersUser2();
结果:
resultType和resultMap实现一对一的对比:
resultType方式实现简单,如果pojo中没有包括查询出来的列名,就再添加需要的列名。
resultMap方式需要在xml中单独定义resultMap,实现要麻烦一点。但是resultMap可以实现延迟加载。
使用resultMap方式实现一对多:
例2,假如在上面的查询中再将订单明细的查询添加进去,那么由于一个订单可能有多个订单明细,所以如果使用resultType方式的话会比较麻烦,需要将查询出来的整条信息作为整体放到list中,在手动对结果进行解析。
sql定义如下:
select orders.*,user.username,user.sex,user.address,user.birthday,orderdetail.id orderdetail_id,orderdetail.items_id,orderdetail.orders_id,orderdetail.items_num
from user,orders,orderdetail
where user.id = orders.user_id and orders.id = orderdetail.orders_id
查询结果:
首先,新建OrderDetail类,在Orders中定义装Orderdetail的List集合List,并设置getter和setter。
然后编写xml:
<resultMap type="com.hhh.dao.Orders" id="orderUserAndDetail">
<id column="id" property="id"/>
<result column="user_Id" property="user_Id"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<association property="user" javaType="com.hhh.dao.User">
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<result column="address" property="address"/>
</association>
<!-- collection对关联查询到多条记录映射到集合对象中
ofType:集中中装的pojo的类型
-->
<collection property="orderdetails" ofType="com.hhh.dao.OrderDetail">
<id column="orderdetail_id" property="id"/>
<result column="items_id" property="items_id"/>
<result column="orders_id" property="orders_id"/>
<result column="items_num" property="items_num"/>
</collection>
</resultMap>
<select id="findOrderUserAndDetail" resultMap="orderUserAndDetail">
select orders.*,user.username,user.sex,user.address,user.birthday,orderdetail.id orderdetail_id,orderdetail.items_id,orderdetail.orders_id,orderdetail.items_num
from user,orders,orderdetail
where user.id = orders.user_id and orders.id = orderdetail.orders_id
</select>
这里resultMap的定义很多地方都与上一个例子中的内容相似,可以在resultMap节点中定义extends继承上一个resultMap的内容,然后省略相同的内容。
方法定义:
public List<Orders> findOrderUserAndDetail() throws Exception;
测试:
List<Orders> list = mapper.findOrderUserAndDetail();
结果:
使用resultMap实现多对多
例3,在上面的条件下,再要求将商品的信息映射进去,主查询为User
要实现的结构:
User中定义一个List装Orders
Order中定义一个List装OrderDetail
OrderDetail中定义属性Items
sql:
select orders.*,user.username,user.sex,user.address,user.birthday,orderdetail.id orderdetail_id,orderdetail.items_id,orderdetail.orders_id,orderdetail.items_num,items.name,items.price,items.pic,items.detail,items.createtime
from user,orders,orderdetail,items
where user.id = orders.user_id and orders.id = orderdetail.orders_id and orderdetail.items_id = items.id
根据上面的结构编辑类
编写xml
<resultMap type="com.hhh.dao.User" id="UserItems">
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<result column="address" property="address"/>
<collection property="orders" ofType="com.hhh.dao.Orders">
<id column="id" property="id"/>
<result column="user_Id" property="user_Id"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<collection property="orderdetails" ofType="com.hhh.dao.OrderDetail">
<id column="orderdetail_id" property="id"/>
<result column="items_id" property="items_id"/>
<result column="orders_id" property="orders_id"/>
<result column="items_num" property="items_num"/>
<association property="items" javaType="com.hhh.dao.Items">
<id column="items_id" property="id"/>
<result column="name" property="name"/>
<result column="price" property="price"/>
<result column="detail" property="detail"/>
<result column="pic" property="pic"/>
<result column="createtime" property="createtime"/>
</association>
</collection>
</collection>
</resultMap>
<select id="findUserItems" resultMap="UserItems">
select orders.*,user.username,user.sex,user.address,user.birthday,orderdetail.id orderdetail_id,orderdetail.items_id,orderdetail.orders_id,orderdetail.items_num,items.name,items.price,items.pic,items.detail,items.createtime
from user,orders,orderdetail,items
where user.id = orders.user_id and orders.id = orderdetail.orders_id and orderdetail.items_id = items.id
</select>
方法定义:
public List<User> findUserItems() throws Exception;
测试:
List<User> list = mapper.findUserItems();
结果:
关于使用resultMap还是resultType:
其实上述的很多东西用resultType就可以轻松完成的,只不过基于题意来达到练习的效果。如果是要求查询用户的商品信息,可以直接将这些东西定义成一个pojo,然后用resultType就可以很容易查询出来。但是使用resultMap的话可以应对一些特殊需求。总是怎么用需要看实际的业务需求。
延迟加载:
使用resultMap中的association、collection是具备延迟加载的功能的。
延迟加载就是查询的时候先从单表查询,然后有需求的时候再去关联查询。这样做可以很大减少数据库的开销,尤其是连接的表比较多的时候。
例4,使用延迟加载的方式查询订单并且关联查询用户信息。
延迟加载是可以手动进行的。
1,首先定义两个查询语句。并实现对应的方法。
2,使用其中的一个语句查询出订单信息。
3,遍历订单信息的List,然后在循环中使用另外一个语句来查询出当前订单的用户信息。
下面以association的方式为例,介绍mybatis的延迟加载机制:
编写xml:
<resultMap type="com.hhh.dao.Orders" id="OrderUserLazyLoading">
<id column="id" property="id"/>
<result column="user_Id" property="user_Id"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<!--
select:指定延迟加载使用的statement的id,如果使用的statement不在本mapper中,需要在id前面加上 命名空间.
column:主查询中关联子查询的列名
如,select *,
(select username from user where user.id = orders.user_id) username
from orders
,这里的column应该是orders表中的user_id
-->
<association property="user" select="findUserById" column="user_id">
<id column="user_id" property="id"/>
<result column="username" property="username"/>
</association>
</resultMap>
<select id="findUserById" parameterType="int" resultType="com.hhh.dao.User">
select * from user where id = #{id}
</select>
<select id="findOrderUserLazyLoading" resultMap="OrderUserLazyLoading">
select * from orders
</select>
在SqlMapConfig.xml中配置:
<!-- 配置延迟加载 -->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
编写方法:
public User findUserById(int id) throws Exception;
public List<Orders> findOrderUserLazyLoading() throws Exception;
测试方法:
List<Orders> orders = mapper.findOrderUserLazyLoading();
for (Orders order : orders) {
//通过get的方式,mybatis实现延迟加载
User user = order.getUser();
System.out.println(user.getUsername());
}