MyBatis框架功能与Hibernate一样。
都是持久化框架。都是操作JDBC。做ORM框架。
1 MyBatis框架比Hibernate小。
2 做的是针对SQL语句查询结果进行封装。
MyBatis是一个针对SQL语句的ORM持久化框架。
1 针对SQL语句
在MyBatis框架中,我们要写SQL语句,针对SQL查询的结果进行封装。
2 ORM
将查询结果可以封装成一个实体对象。
3 持久化
使用JDBC进行数据库操作。
在src目录下创建mybatis.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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/t2?useUnicode=true&characterEncoding=utf8" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
</configuration>
1 数据库表:goods_type
2 编写实体类:GoodsType
public class GoodsType {
private int typeId;
private String typeName;
在MyBatis框架中SQL语句是程序员自己编写。
在MyBatis框架时,编写的SQL语句是独立于java源文件之外。
1 编写在xml配置文件(推荐)
2 编写在方法的注解
注意:编写一个与类名同名的xml文件。
在这个xml中编写对应的CURD的SQL语句。
<?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.zpark.tea_mgr.domain.GoodsType">
<select id="findAll" resultType="com.zpark.tea_mgr.domain.GoodsType">
select * from goods_type
</select>
</mapper>
resultType="com.no1.domain.GoodsType"
表示查询结果的每一条记录封装成指定的类型。
(只有在字段名称与属性名称一致时可用)
<?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>
<environments default="development">……</environments>
<mappers>
<mapper resource="com/zpark/tea_mgr/domain/GoodsType.xml" />
</mappers>
</configuration>
在MyBatis中使用核心组件SqlSession进行CRUD操作。
@Before
public void before() {
try {
String resource = "mybatis.xml";
Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);
this.sqlSession = ssf.openSession();
} catch (IOException e) {
e.printStackTrace();
}
}
查询所有
public void test01() {
try {
List<GoodsType> goodsTypeList = this.sqlSession.selectList("com.zpark.tea_mgr.domain.GoodsType.findAll");
for (GoodsType goodsType : goodsTypeList) {
System.out.println(goodsType);
}
} catch(Exception e) {
e.printStackTrace();
} finally {
this.sqlSession.close();
}
}
Q:为什么要配置DTD文件?
DTD相当于是编写XML文件的代码提示蓝本,在XML文件中声明DTD的ID或者URL,再在MyEclipse或者Eclipse中配置一下,重新打开这个XML文件,就可以用alt+/获得像编写JAVA代码一样的提示功能。具体的配置方法可以百度一下~
当然,这个文件主要的功能是验证XML文件编写的合法性,也就是一个约束,要求你只能按DTD定义的格式写。
建议去看一下XML相关知识。
5.4 在mybatis.xml文件中注册Goods.xml文件
在实际开发中,不直接使用SqlSession的实例,而是使用Mapper接口,构建dao层。
映射器是你创建的绑定映射语句的接口(interface)
映射器接口的实例可以从SqlSession中获得
public class Goods {
// goods_id int
private int goodsId;
// goods_name varchar
private String goodsName;
// goods_price double
private double goodsPrice;
// goods_num int
private int goodsNum;
// goods_type int
private int goodsType;
}
Mapper接口相当于Hebernate中的DAO
在这个接口中声明针对Goods这个实体类进行哪些CRUD操作
public interface GoodsMapper {
public List<Goods> findAll();
}
在MyBatis框架中,接口的实现类是一个XML文件
在GoodsMapper接口的同目录创建一个叫GoodsMapper.xml文件
<mapper namespace="com.zpark.tea_mgr.mapper.GoodsMapper">
<select id="findAll" resultMap="resultGoods">
select * from goods
</select>
<resultMap type="com.zpark.tea_mgr.domain.Goods" id="resultGoods">
<id property="goodsId" column="goods_id" javaType="int" />
<result property="goodsName" column="goods_name" javaType="java.lang.String" />
<result property="goodsPrice" column="goods_price" javaType="double" />
<result property="goodsNum" column="goods_num" javaType="int" />
<result property="goodsType" column="goods_type" javaType="int" />
</resultMap>
</mapper>
<configuration>
<environments default="development">……</environments>
<mappers>
<mapper resource="com/zpark/tea_mgr/mapper/GoodsMapper.xml" />
</mappers>
</configuration>
GoodsMapper goodsMapper = this.sqlSession.getMapper(GoodsMapper.class);
只有一个参数时,在xml文件中只要制定类型就可以
在sql语句中可以使用任意名称的参数
public Goods findById(int id);
<select id="findById" parameterType="int" resultMap="resultGoods">
select * from goods
where goods_id = #{id}
</select>
按价格区间查询的方法
public List<Goods> findByPrice(
@Param("minPrice") double minPrice, @Param("maxPrice") double maxPrice);
<select id="findByPrice" resultMap="resultGoods">
select * from goods
where goods_price between #{minPrice} and #{maxPrice}
</select>
这个时候不用写parameterType
参数
public void save(Goods goods);
<insert id="save" parameterType="com.zpark.tea_mgr.domain.Goods">
insert into goods(goods_id, goods_name, goods_price, goods_type)
values(#{goodsId}, #{goodsName}, #{goodsPrice}, #{goodsType})
</insert>
try {
GoodsMapper goodsMapper = this.sqlSession.getMapper(GoodsMapper.class);
Goods goods = new Goods();
goods.setGoodsName("测试用商品A");
goods.setGoodsPrice(6666);
goods.setGoodsNum(66);
goods.setGoodsType(4);
goodsMapper.save(goods);
this.sqlSession.commit();
System.out.println("新增商品成功");
} catch(Exception e){
e.printStackTrace();
this.sqlSession.rollback();
throw new RuntimeException(e);
} finally{
this.sqlSession.close();
}
public class GoodsSearchVO {
private String goodsName;
private double minPrice;
private double maxPrice;
……
public List<Goods> findBySearchVO(GoodsSearchVO goodsSearchVO);
<select id="findBySearchVO"
parameterType="com.zpark.tea_mgr.vo.GoodsSearchVO" resultMap="resultGoods">
select * from goods
where goods_name like concat('%', concat(#{goodsName}, '%'))
and goods_price between #{minPrice} and #{maxPrice}
</select>
try {
GoodsMapper goodsMapper
= this.sqlSession.getMapper(GoodsMapper.class);
GoodsSearchVO goodsSearchVO = new GoodsSearchVO("球", 100, 300);
List<Goods> goodsList
= goodsMapper.findBySearchVO(goodsSearchVO);
for (Goods goods : goodsList) {
System.out.println(goods);
}
} finally{
this.sqlSession.close();
}
查询所有的商品的最大价格和最小价格
public class GoodsGroupVO {
private double minPrice;
private double maxPrice;
public GoodsGroupVO findByGroup();
<select id="findByGroup" resultType="com.zpark.tea_mgr.vo.GoodsGroupVO">
select
min(goods_price) as 'minPrice',
max(goods_price) as 'maxPrice'
from goods
</select>
MySQL: limit 索引, 个数
Oracle: 二层子查询 + rownum
需要使用的jar文件
项目中的jar包
在mybatis.xml文件中注册插件
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql" />
</plugin>
</plugins>
分页插件使用一个静态方法设置
有效范围: 进队后面的第一个查询有效
PageHelper.startPage(1, 2);
List<Goods> goodsList = goodsMapper.findAll();
PageHelper.startPage(int pageNum, int size);
1、 int pageNum
当前页码, 从 1 开始
2、 int size
每页记录数量
比如当前页吗,总记录数量等
通过这些信息进行页面分页控制。 上一页, 下一页
在分页插件中提供了一个叫PageInfo
的类,这个类封装了分页的相关信息
通过构造方法装载分页的集合对象
PageInfo<Goods> pageInfo = new PageInfo<Goods>(goodsList);
分页相关信息的方法使用
try{
GoodsMapper goodsMapper
= this.sqlSession.getMapper(GoodsMapper.class);
PageHelper.startPage(1, 2);
List<Goods> goodsList = goodsMapper.findAll();
PageInfo<Goods> pageInfo = new PageInfo<Goods>(goodsList);
for (Goods goods : pageInfo.getList()) {
System.out.println(goods);
}
System.out.println("当前页码:" + pageInfo.getPageNum());
System.out.println("每页记录数:" + pageInfo.getPageSize());
System.out.println("总页码数:" + pageInfo.getPages());
System.out.println("总记录数:" + pageInfo.getTotal());
System.out.println("上一页:" + pageInfo.getPrePage());
System.out.println("下一页:" + pageInfo.getNextPage());
} finally{
this.sqlSession.close();
}
注意控制上一页,下一页合理范围(上一页不会 <= 0, 下一页不会 超过总页码),相关的if语句自己完成
在MyBatis的框架中可以进行关联关系的映射,但是种类没有Hibernate那么多
第一类: 对一 有一个实体类需要映射
第二类: 对多 有一个集合需要映射
现在只处理对一的情况,所以在Goods类中有一个GoodsType类的对象
public class GoodsType {
private int typeId;
private String typeName;
public class Goods {
private int goodsId;
private String goodsName;
private double goodsPrice;
private int goodsNum;
private GoodsType goodsType;
Goods
类最后一个属性 设计为GoodsType
类型,表明对一关系
public interface GoodsMapper {
public List<Goods> findAll();
在这个XML文件中配置关联对象的映射,在MyBatis中有三种解决方案可选
直接通过对象打点调用属性的方式做映射
要求: 查询语句要使用连接查询
<!-- 第一种方案:使用连接查询 -->
<select id="findAll" resultMap="resultGoods">
select * from goods
left join goods_type
on goods_type.typeId = goods.goods_type
</select>
<resultMap type="com.zpark.tea_mgr.domain.Goods" id="resultGoods">
<id property="goodsId" column="goods_id" javaType="int" />
<result property="goodsName" column="goods_name" javaType="java.lang.String" />
<result property="goodsPrice" column="goods_price" javaType="double" />
<result property="goodsNum" column="goods_num" javaType="int" />
<!-- 第一种方案:直接使用打点调用属性的方式 -->
<result property="goodsType.typeId" column="typeId" javaType="int" />
<result property="goodsType.typeName" column="typeName" javaType="java.lang.String" />
</resultMap>
引用关联关系对象的Mapper映射
GoodsTypeMapper.xml文件
<resultMap type="com.zpark.tea_mgr.domain.GoodsType" id="resultGoodsType">
<id property="typeId" column="typeId" javaType="int" />
<result property="typeName" column="typeName"
javaType="java.lang.String" />
</resultMap>
GoodsMapper.xml文件
<association property="goodsType"
javaType="com.zpark.tea_mgr.domain.GoodsType" resultMap="com.zpark.tea_mgr.mapper.GoodsTypeMapper.resultGoodsType" />
调用关联关系对象的Mapper的查询方法
public interface GoodsTypeMapper {
public GoodsType findById(int typeId);
<select id="findById" parameterType="int" resultMap="resultGoodsType">
select * from goods_type where typeId = #{id}
</select>
GoodsMapper.xml中
<!-- 第三种方案: 查自己就好了 -->
<select id="findAll" resultMap="resultGoods">
select * from goods
</select>
<!-- 第三种方案: 使用关联关系对象的查询的方法 -->
<association property="goodsType"
javaType="com.zpark.tea_mgr.domain.GoodsType"
select="com.zpark.tea_mgr.mapper.GoodsTypeMapper.findById"
column="goods_type" />
一个类型有多个商品
设计为: 在类型类中有一个商品的集合
public class GoodsType {
private int typeId;
private String typeName;
private List<Goods> goodsList;
public interface GoodsTypeMapper {
public List<GoodsType> findAll();
映射从一个类型到多个商品
<select id="findAll" resultMap="resultGoodsType">
select * from goods_type
left join goods
on goods.goods_type = goods_type.typeId
</select>
<resultMap type="com.zpark.tea_mgr.domain.GoodsType" id="baseGoodsType">
<id property="typeId" column="typeId" javaType="int" />
<result property="typeName" column="typeName"
javaType="java.lang.String" />
</resultMap>
<resultMap type="com.zpark.tea_mgr.domain.GoodsType" id="resultGoodsType"
extends="baseGoodsType">
<collection property="goodsList" javaType="java.util.List"
ofType="com.zpark.tea_mgr.domain.Goods"
resultMap="com.zpark.tea_mgr.mapper.GoodsMapper.resultGoods"
/>
</resultMap>
public interface GoodsMapper {
public List<Goods> findByType(int goodsTypeId);
<select id="findByType" parameterType="int" resultMap="resultGoods">
select * from goods where goods_type = #{id}
</select>
<!-- 第二种方案 -->
<collection property="goodsList" javaType="java.util.List"
ofType="com.zpark.tea_mgr.domain.Goods"
select="com.zpark.tea_mgr.mapper.GoodsMapper.findByType"
column="typeId" />
** 但要提供查询的方法,在业务层完成组装**
public class Goods implements Serializable{
private static final long serialVersionUID = 8874153057031505335L;
private Integer goodsId;
private String goodsName;
private Double goodsPrice;
private Integer goodsNum;
private GoodsType goodsType;
public class GoodsType {
private Integer typeId;
private String typeName;
private List<Goods> goodsList;
public interface GoodsMapper {
public List<Goods> findAll();
/**
* 给关联关系对象(商品类型)提供查找其下商品的方法
* 如果要查某个商品类型信息的时候要带出相关的商品信息
* @param typeId 某个商品类型的ID
* @return 返回某个商品类型下的商品集
*/
public List<Goods> findByType(int typeId);
public interface GoodsTypeMapper {
public List<GoodsType> findAll();
public GoodsType findById(int typeId);
针对对象在编写查询语句时,直接使用连接查询
<select id="findAll" resultMap="BaseResultMap">
select * from goods
left join goods_type
on goods_type.typeId = goods.goods_type
</select>
<select id="findByType" parameterType="java.lang.Integer"
resultMap="BaseResultMap">
select * from goods
left join goods_type
on goods_type.typeId = goods.goods_type
where goods_type = #{id}
</select>
编写映射时直接关联关系对象的resultMap映射
<resultMap type="com.zpark.tea_mgr.domain.Goods" id="BaseResultMap">
<id column="goods_id" property="goodsId" jdbcType="INTEGER" />
<result column="goods_name"
property="goodsName" jdbcType="VARCHAR" />
<result column="goods_price" property="goodsPrice" jdbcType="DOUBLE" />
<result column="goods_num" property="goodsNum" jdbcType="INTEGER" />
<association property="goodsType"
javaType="com.zpark.tea_mgr.domain.GoodsType" resultMap="com.zpark.tea_mgr.mapper.GoodsTypeMapper.BaseResultMap" />
</resultMap>
针对集合,不用连接查询集合的数据
<select id="findAll" resultMap="BaseResultMap">
select * from goods_type
</select>
<select id="findById" parameterType="java.lang.Integer"
resultMap="BaseResultMap">
select * from goods_type
where typeId = #{id}
</select>
针对集合映射时,不要映射集合
<resultMap type="com.zpark.tea_mgr.domain.GoodsType" id="BaseResultMap">
<id property="typeId" column="typeId" javaType="java.lang.Integer" />
<result column="typeName" property="typeName" jdbcType="VARCHAR" />
</resultMap>
public class GoodsTypeService {
public GoodsType findById(int typeId){
SqlSession sqlSession = null;
try{
String resource = "mybatis.xml";
Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);
sqlSession = ssf.openSession();
GoodsTypeMapper goodsTypeMapper =
sqlSession.getMapper(GoodsTypeMapper.class);
GoodsType goodsType = goodsTypeMapper.findById(typeId);
GoodsMapper goodsMapper =
sqlSession.getMapper(GoodsMapper.class);
List<Goods> goodsList = goodsMapper.findByType(typeId);
// 组装
goodsType.setGoodsList(goodsList);
return goodsType;
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException(e);
}finally{
sqlSession.close();
}
}
}
public interface GoodsMapper {
public void update(Goods goods);
public Goods findById(int goodsId);
public void updateByDynamicSQL(Goods goods);
<update id="updateByDynamicSQL"
parameterType="com.zpark.tea_mgr.domain.Goods">
update goods
<set>
<if test="goodsName != null">
goods_name = #{goodsName},
</if>
<if test="goodsPrice != null">
goods_price = #{goodsPrice},
</if>
<if test="goodsNum != null">
goods_num = #{goodsNum},
</if>
<if test="goodsType != null and goodsType.typeId != null">
goods_type = #{goodsType.typeId},
</if>
</set>
where goods_id = #{goodsId}
</update>
使用动态SQL,我们要修改商品,可以不必先从数据库中查询出来
public class GoodsSearchVO {
private String goodsName;
private Double minPrice;
private Double maxPrice;
public List<Map<String, Object>> findBySearchVO(GoodsSearchVO goodsSearchVO);
<select id="findBySearchVO"
parameterType="com.zpark.tea_mgr.vo.GoodsSearchVO"
resultType="java.util.Map">
select
goods_name as 'goodsName',
goods_price as 'goodsPrice',
goods_num as 'goodsNum',
typeName as 'typeName'
from goods
left join goods_type
on goods_type.typeId = goods.goods_type
<where>
<if test="goodsName != null">
goods_name like concat('%', #{goodsName}, '%')
</if>
<if test="minPrice != null">
and goods_price > #{minPrice}
</if>
<if test="maxPrice != null">
and goods_price < #{maxPrice}
</if>
</where>
</select>
批量插入
public void saveBat(List<Goods> goodsList);
<insert id="saveBat" parameterType="java.util.List">
insert into goods (goods_name, goods_price, goods_num, goods_type)
values
<foreach collection="list" item="goods" separator=",">
(#{goods.goodsName}, #{goods.goodsPrice}, #{goods.goodsNum},
#{goods.goodsType.typeId})
</foreach>
</insert>
批量删除
public void delBat(List<Integer> seq);
<delete id="delBat" parameterType="java.util.List">
delete from goods
where goods_id in
<foreach collection="list" item="id" separator="," open="(" close=")"
index="index">
#{id}
</foreach>
</delete>
1.spring抢MyBatis的连接
2 Spring抢Mapper接口
3 spring抢Mapper.xml文件
导入MyBatis框架
导入Spring框架
1 MyBatis的配置文件中不用写连接参数
2 在applicationContext.xml文件中配置数据源
3配置一个MyBatis的sqlSessionFactory
@Repository("GoodsMapper")
public interface GoodsMapper {
public List<Goods> findAll();
public void save(Goods goods);
}
Mapper.xml文件没有什么改动,这里不再提供了
@Repository("GoodsTypeMapper")
public interface GoodsTypeMapper {
@Service("GoodsService")
public class GoodsService {
@Autowired
@Qualifier("GoodsMapper")
private GoodsMapper goodsMapper;
public GoodsMapper getGoodsMapper() {
return goodsMapper;
}
public void setGoodsMapper(GoodsMapper goodsMapper) {
this.goodsMapper = goodsMapper;
}
@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
public List<Goods> findAll(){
try{
return this.goodsMapper.findAll();
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException(e);
}
}
@Transactional(propagation = Propagation.REQUIRED,
rollbackFor = { Exception.class })
public void save(Goods goods){
try{
this.goodsMapper.save(goods);
System.out.println("保存成功!");
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
Albert.Zhou.CH总结 前辈经验于此,与各位分享
2019-03-20
-------------------------------To be continued------------------------------