MVC模型
Model模型:JavaBean实现,用于封装业务数据UserBean和业务逻辑UserDaoImpl
View视图:JSP+JSTL实现,用于收集客户动作<form>
和显示业务数据<table>
Controller控制器:Servlet实现,用于流程控制
MyBatis开发步骤
1、添加依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2、定义核心配置文件 resources/mybatis-config.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="database.properties"/>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
</configuration>
3、创建表
create table t_users(
id bigint primary key auto_increment,
username varchar(20) not null unique,
password varchar(20) not null
)engine=innodb default charset utf8;
根据表结构定义对应的实体类
@Data
public class UserBean implements Serializable {
private Long id;
private String username;
private String password;
}
定义对应的映射元文件 resources/com/yan/mapper/UserBean-mapper.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>
<resultMap id="baseResultMapper" type="com.yan.entity.UserBean" autoMapping="true">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="password" property="password" jdbcType="VARCHAR"/>
</resultMap>
<insert id="save" parameterType="com.yan.entity.UserBean" useGeneratedKeys="true" keyProperty="id">
insert into t_users(username,password) values(#{username},#{password})
</insert>
</mapper>
jdbcType的设置名称对应的是java.jdbc.Types类中的常量名称
定义映射文件后需要在核心配置文件中进行注册 mybatis-config.xml
<mappers>
<mapper resource="com/yan/mapper/UserBean-mapper.xml"/>
</mappers>
目前一般建议使用Mapper接口的方式进行调用,所以需要添加对应的Mapper接口
public interface UserMapper {
//对应映射元文件中的insert\update\delete\select标签
int save(UserBean user);
}
修改映射元文件的名空间和Mapper接口的全名一致
<mapper namespace="com.yan.mapper.UserMapper">
4、定义工具类
重点:4大核心组件的生命周期
public class MybatisSessionFactory {
private MybatisSessionFactory(){}
private static SqlSessionFactory factory=null;
private static final ThreadLocal<SqlSession> sessions=new ThreadLocal<>();
SqlSession是java.sql.Connection对象的浅封装,必须保证及时关闭
public class OpenSessionInViewFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
try{
chain.doFilter(request, response);
MybatisSessionFactory.commitTransaction();
} catch (Exception e){
MybatisSessionFactory.rollbackTransaction();
throw new ServletException(e);
}finally {
MybatisSessionFactory.closeSession();
}
}
}
Filter的配置信息 web.xml
<filter>
<filter-name>OpenSessionInView</filter-name>
<filter-class>com.yan.filters.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenSessionInView</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
多表关联的问题
对一查询
学生和班级【产品和类目】
create table t_catalog(
id bigint primary key auto_increment,
title varchar(32) not null
)engine=innodb default charset utf8;
create table t_produce(
id bigint primary key auto_increment,
name varchar(32) not null,
catalog_id bigint,
foreign key(catalog_id) references t_catalog(id) on delete cascade
)engine=innodb default charset utf8;
定义实体类
按照业务分析,可以发现获取类目信息时不需要加载对应类型的产品信息,所以这是一个单向关联关系
public class CatalogBean implements Serializable{
private Long id;
private String title;
}
多方的类定义,需要获取一方的信息
public class ProduceBean implements Serializable{
private Long id;
private String name;
private CatalogBean catalog=new CatalogBean();
}
定义映射元文件
如何实现获取产品信息时同时获取对应的类目信息?
写法1:使用级联属性定义
<?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.yan.mapper.ProduceMapper">
<resultMap id="baseResultMap" type="com.yan.entity.ProduceBean">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<result column="catalog_id" property="catalog.id" jdbcType="BIGINT"/>
<result column="title" property="catalog.title" jdbcType="VARCHAR"/>
</resultMap>
<select id="loadById" parameterType="long" resultMap="baseResultMap">
select p.*,c.title from t_produce p left join t_catalog c on p.catalog_id=c.id where p.id=#{id}
</select>
</mapper>
写法2:推荐使用
<resultMap id="baseResultMap" type="com.yan.entity.ProduceBean">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<association property="catalog" javaType="com.yan.entity.CatalogBean">
<id column="catalog_id" property="id" jdbcType="BIGINT"/>
<result column="title" property="title" jdbcType="VARCHAR"/>
</association>
</resultMap>
<select id="loadById" parameterType="long" resultMap="baseResultMap">
select p.*,c.title from t_produce p left join t_catalog c on p.catalog_id=c.id where p.id=#{id}
</select>
写法3:不推荐使用
<resultMap id="baseResultMap" type="com.yan.entity.ProduceBean">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<association property="catalog" select="com.yan.mapper.CatalogMapper.loadById" column="catalog_id"/>
</resultMap>
<select id="loadById" parameterType="long" resultMap="baseResultMap">
select * from t_produce where id=#{id}
</select>
###association对一
-
select:另一个映射查询的id,MyBatis会额外执行这个查询获取嵌套对象的结果。
-
column:将主查询中列的结果作为嵌套查询的参数,配置方式如column="{prop1=col1,prop2=col2}",prop1和prop2将作为嵌套查询的参数。
-
fetchType:数据加载方式,可选值为lazy和eager分别为延迟加载和积极加载。
-
如果要使用延迟加载,除了将fetchType设置为lazy,还需要注意全局配置aggressiveLazyLoading的值应该为false。这个参数在3.4.5版本之前默认值为ture,从3.4.5版本开始默认值改为false
对多查询
获取订单信息时需要获取对应的订单详情信息
create table t_order(
id bigint primary key auto_increment
order_date timestamp default current_timestamp,
all_price numeric(8,2)
)engine=innodb default charset utf8;
create table t_order_item(
id bigint primary key auto_increment,
produce_id bigint not null,
price numeric(8,2),
num int default 1,
order_id bigint not null,
foreign key(order_id) references t_order(id) on delete cascade
)engine=innodb default charset utf8;
实体类定义
一般查询订单详细信息时,需要加载对应的订单详情信息
public class OrderBean implements Serializable{
private Long id;
private Date orderDate;
private Double allPrice;
private Set<OrderItemBean> items=new HashSet<>(0); //0这个参数实际上含义在于避免不存储数据但是开辟空间,实际上JDK1.8中HashMap无参构建时已经使用了延迟初始化数组的处理,所以0不是必须的
}
订单详情类
public class OrderItemBean implements Serializable{
private Long id;
private Long produceId;
private Double price;
private Integer num;
}
定义映射元文件
如何实现获取订单信息时同时获取对应的订单详情信息?
方法1:
<mapper namespace="com.yan.mapper.OrderMapper">
<resultMap id="baseResultMap" type="com.yan.entity.OrderBean">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="order_date" property="orderDate" jdbcType="TIMESTAMP"/>
<result column="all_price" property="allPrice" jdbcType="NUMERIC"/>
</resultMap>
<resultMap id="extResultMap" extends="baseResultMap" type="com.yan.entity.OrderBean">
<collection property="items" ofType="com.yan.entity.OrderItemBean" select="selectByOrderId" column="id"/>
</resultMap>
<select id="loadById" resultMap="extResultMap" parameterType="long">
select * from t_order where id=#{id}
</select>
<select id="selectAll" resultMap="baseResultMap">
select * from t_order
</select>
<select id="selectByOrderId" resultType="com.yan.entity.OrderItemBean">
select * from t_order_item where order_id=#{id}
</select>
</mapper>
修改接口定义
public interface OrderMapper {
OrderBean loadById(Long id);
List<OrderItemBean> selectByOrderId(long id);
}
方法2:
<resultMap id="baseResultMap" type="com.yan.entity.OrderBean">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="order_date" property="orderDate" jdbcType="TIMESTAMP"/>
<result column="all_price" property="allPrice" jdbcType="NUMERIC"/>
</resultMap>
<resultMap id="extResultMap" extends="baseResultMap" type="com.yan.entity.OrderBean">
<collection property="items" ofType="com.yan.entity.OrderItemBean">
<id column="item_id" property="id" jdbcType="BIGINT"/>
<result column="produce_id" property="produceId" jdbcType="BIGINT"/>
<result column="num" property="num" jdbcType="NUMERIC"/>
</collection>
</resultMap>
<select id="loadById" resultMap="extResultMap" parameterType="long">
select od.*,it.id item_id,it.produce_id,it.num from t_order od left join t_order_item it on od.id=it.order_id where od.id=#{id}
</select>
###collection对多
-
select:另一个映射查询的id,MyBatis会额外执行这个查询获取嵌套对象的结果。
-
column:将主查询中列的结果作为嵌套查询的参数,配置方式如column="{prop1=col1,prop2=col2}",prop1和prop2将作为嵌套查询的参数。
-
fetchType:数据加载方式,可选值为lazy和eager,分别为延迟加载和积极加载。
-
如果要使用延迟加载,除了将fetchType设置为lazy,还需要注意全局配置aggressiveLazyLoading的值应该为false