MyBatis入门
第1章 MyBatis介绍
1-1 框架的作用
- Spring提供了底层的对象管理,
- Spring MVC提供了Web层面的交互(替代SERVLET web开发)
- Mybatis 提供了数据库的增删改查的便捷操作
- SSM是软件框架的框架
1-2 介绍MyBatis
dao是指数据访问层,就是对数据库的增删改查操作,业务逻辑层就是指service层,调用dao层方法,获取结果并根据业务需要对数据进一步的处理。而servlet是用于和JSP等前端页面交互,接收参数并转发。
Java的三层架构就是将整个业务应用划分为:表示层(User Interface layer)、业务逻辑层(Business Logic Layer)、数据访问层
- MyBatis开发流程
- 引入MyBatis依赖
- 创建核心配置文件
- 创建实体(Entity)类
- 创建Mapper映射文件
- 初始化SessionFactory(会话工厂)
- 利用SqlSession对象操作数据
第2章 MyBatis基本使用
2-1 MyBatis环境配置
- pom.xml中引入Mybatis依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
- IDEA右侧提供它内置的database
- 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>
<settings>
<!-- goods_id ==> goodsId 驼峰命名转换 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--启用Pagehelper分页插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!--设置数据库类型-->
<property name="helperDialect" value="mysql"/>
<!--分页合理化-->
<property name="reasonable" value="true"/>
</plugin>
</plugins>
<!--设置默认指向的数据库-->
<environments default="dev">
<!--配置环境,不同的环境不同的id名字-->
<environment id="dev">
<!-- 采用JDBC方式对数据库事务进行commit/rollback -->
<transactionManager type="JDBC"></transactionManager>
<!--采用连接池方式管理数据库连接-->
<!--<dataSource type="POOLED">-->
<dataSource type="com.imooc.mybatis.datasource.C3P0DataSourceFactory">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/babytun?useUnicode=true&characterEncoding=UTF-8"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
<property name="initialPoolSize" value="5"/>
<property name="maxPoolSize" value="20"/>
<property name="minPoolSize" value="5"/>
<!--...-->
</dataSource>
</environment>
<environment id="prd">
<!-- 采用JDBC方式对数据库事务进行commit/rollback -->
<transactionManager type="JDBC"></transactionManager>
<!--采用连接池方式管理数据库连接-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.1.155:3306/babytun?useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mappers/goods.xml"/>
<mapper resource="mappers/goods_detail.xml"/>
</mappers>
</configuration>
2-3 SqlSessionFactory
- SqlSessionFactory本质上就是加载配置文件(mybatis-config.xml),完成Mybatis框架的初始化操作
- SqlSession(学习重点)
- 数据库的增删改查是由SqlSessionFactory这个工厂类创建的SqlSession对象实现的
- SqlSessionFactory加载配置文件,并通过SqlSession建立数据库链接
/**
* 初始化SqlSessionFactory
* @throws IOException
*/
@Test
public void testSqlSessionFactory() throws IOException {
//利用Reader加载classpath下的mybatis-config.xml核心配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//初始化SqlSessionFactory对象,同时解析mybatis-config.xml文件
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
System.out.println("SessionFactory加载成功");
SqlSession sqlSession = null;
try {
//创建SqlSession对象,SqlSession是JDBC的扩展类,用于与数据库交互
sqlSession = sqlSessionFactory.openSession();
//创建数据库连接(测试用)
Connection connection = sqlSession.getConnection();
System.out.println(connection);
}catch (Exception e){
e.printStackTrace();
}finally {
if(sqlSession != null){
//如果type="POOLED",代表使用连接池,close则是将连接回收到连接池中
//如果type="UNPOOLED",代表直连,close则会调用Connection.close()方法关闭连接
sqlSession.close();
}
}
}
2-5 初始化工具类MyBatisUtils
-
MyBatisUtils的主要作用就是初始化SqlSessionFactory会话工程
- 要求SqlSessionFactory在全局应用中唯一,
-
如何保证SqlSessionFactory全局唯一:
通过创建额外的工具类MybatisUtils对SqlSessionFactory对象的初始化以及SqlSession对象的创建和释放方法进行封装 。 -
注:
- 1、一般工具类放在utils包下;
- 2、用static代码块对静态对象进行初始化;
- 3、这边我们在异常捕获后将类的初始化的过程中产生的异常抛出,为了外界能捕获到这个异常信息并进行后续处理,而不是直接终止运行程序,我们需要将异常抛出;
- 4、提供SqlSession对象的创建与释放方法,工具类的大多数方法要使用static进行描述。
-
创建额外的工具类MybatisUtils
-
MyBatisUtils.java
package com.imooc.mybatis.utils;
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 java.io.IOException;
import java.io.Reader;
/**
* MyBatisUtils工具类,创建全局唯一的SqlSessionFactory对象
*/
public class MyBatisUtils {
//利用static(静态)属于类不属于对象,且全局唯一
private static SqlSessionFactory sqlSessionFactory = null;
//利用静态块在初始化类时实例化sqlSessionFactory
static {
Reader reader = null;
try {
reader = Resources.getResourceAsReader("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
//初始化错误时,通过抛出异常ExceptionInInitializerError通知调用者
throw new ExceptionInInitializerError(e);
}
}
/**
* openSession 创建一个新的SqlSession对象
* @return SqlSession对象
*/
public static SqlSession openSession(){
//默认SqlSession对自动提交事务数据(commit)
//设置false代表关闭自动提交,改为手动提交事务数据
return sqlSessionFactory.openSession(false);
}
/**
* 释放一个有效的SqlSession对象
* @param session 准备释放SqlSession对象
*/
public static void closeSession(SqlSession session){
if(session != null){
session.close();
}
}
}
- test
/**
* MyBatisUtils使用指南
* @throws Exception
*/
@Test
public void testMyBatisUtils() throws Exception {
SqlSession sqlSession = null;
try {
//通过MyBatisUtils创建SqlSession对象,SqlSession是JDBC的扩展类,用于与数据库交互
sqlSession = MyBatisUtils.openSession();
//创建数据库连接(测试用)
Connection connection = sqlSession.getConnection();
System.out.println(connection);
}catch (Exception e){
throw e;
} finally {
MyBatisUtils.closeSession(sqlSession);
}
}
2-6 MyBatis数据查询
-1 创建实体类Goods
package com.imooc.mybatis.entity;
import java.util.List;
public class Goods {
private Integer goodsId;//商品编号
private String title;//标题
private String subTitle;//子标题
private Float originalCost;//原始价格
private Float currentPrice;//当前价格
private Float discount;//折扣率
private Integer isFreeDelivery;//是否包邮 ,1-包邮 0-不包邮
private Integer categoryId;//分类编号
private List<GoodsDetail> goodsDetails;
//...省去了构造、set、get方法
}
-2. 创建mapper文件–good.xml
- Mapper XML,说明实体对象和数据表的映射关系,及用来说明实体类与数据库中的哪个表对应,实体类的成员变量与数据库表的哪个字段对应。
- resultType 是设置查询结果返回值的类型的
- resultType 是设置查询结果返回值的类型的
- good.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="goods">
<select id="selectAll" resultType="com.imooc.mybatis.entity.Goods">
select * from t_goods order by goods_id desc limit 10
</select>
</mapper>
- 3.开启驼峰命名映射
- 在Myabatis-config.xml中 开启驼峰命名与数据表字段名的转换
查询返回时会自动的将goods_id 转换为 goodsId
settings>
<!-- goods_id ==> goodsId 驼峰命名转换 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
在mybatid-config.xml中声明good.xml文件
- test
/**
* select查询语句执行
* @throws Exception
*/
@Test
public void testSelectAll() throws Exception {
SqlSession session = null;
try{
session = MyBatisUtils.openSession();
List<Goods> list = session.selectList("goods.selectAll");
for(Goods g : list){
System.out.println(g.getTitle());
}
}catch (Exception e){
throw e;
}finally {
MyBatisUtils.closeSession(session);
}
}
- 查询结构
2-7 自由编程
第3章 SQL传参
3-1 SQL传参
-
- 传递单个SQL参数
- good.xml
<!-- 单参数传递,使用parameterType指定参数的数据类型即可,SQL中#{value}提取参数-->
<select id="selectById" parameterType="Integer" resultType="com.imooc.mybatis.entity.Goods">
select * from t_goods where goods_id = #{value}
</select>
- test
/**
* 传递单个SQL参数
* @throws Exception
*/
@Test
public void testSelectById() throws Exception {
SqlSession session = null;
try{
session = MyBatisUtils.openSession();
Goods goods = session.selectOne("goods.selectById" , 1603);
System.out.println(goods.getTitle());
}catch (Exception e){
throw e;
}finally {
MyBatisUtils.closeSession(session);
}
}
-
- 传递多个SQL参数
- 传递多个SQL参数
<!-- 多参数传递时,使用parameterType指定Map接口,SQL中#{key}提取参数 -->
<select id="selectByPriceRange" parameterType="java.util.Map" resultType="com.imooc.mybatis.entity.Goods">
select * from t_goods
where
current_price between #{min} and #{max}
order by current_price
limit 0,#{limt}
</select>
- test
/**
* 传递多个SQL参数
* @throws Exception
*/
@Test
public void testSelectByPriceRange() throws Exception {
SqlSession session = null;
try{
session = MyBatisUtils.openSession();
Map param = new HashMap();
param.put("min",100);
param.put("max" , 500);
param.put("limt" , 10);
List<Goods> list = session.selectList("goods.selectByPriceRange", param);
for(Goods g:list){
System.out.println(g.getTitle() + ":" + g.getCurrentPrice());
}
}catch (Exception e){
throw e;
}finally {
MyBatisUtils.closeSession(session);
}
}
第4章 多表关联查询
4-1 获取多表关联查询结果
- 两个表关联查询
/**
* 利用Map接收关联查询结果
* @throws Exception
*/
@Test
public void testSelectGoodsMap() throws Exception {
SqlSession session = null;
try{
session = MyBatisUtils.openSession();
List<Map> list = session.selectList("goods.selectGoodsMap");
for(Map map : list){
System.out.println(map);
}
}catch (Exception e){
throw e;
}finally {
MyBatisUtils.closeSession(session);
}
}
4-2 选择练习
4-3 ResultMap结果映射
新增一个实体类
- Category.java
package com.imooc.mybatis.entity;
public class Category {
private Integer categoryId;
private String categoryName;
private Integer parentId;
private Integer categoryLevel;
private Integer categoryOrder;
//....省区构造、get、set方法
}
-
dto
-
GoodsDTO.java
package com.imooc.mybatis.dto;
import com.imooc.mybatis.entity.Category;
import com.imooc.mybatis.entity.Goods;
//Data Transfer Object--数据传输对象
public class GoodsDTO {
private Goods goods = new Goods();
private Category category = new Category();
private String test;
//....省区构造、get、set方法
}
- Good.xml
<!--结果映射-->
<resultMap id="rmGoods" type="com.imooc.mybatis.dto.GoodsDTO">
<!--设置主键字段与属性映射-->
<id property="goods.goodsId" column="goods_id"></id>
<!--设置非主键字段与属性映射-->
<result property="goods.title" column="title"></result>
<result property="goods.originalCost" column="original_cost"></result>
<result property="goods.currentPrice" column="current_price"></result>
<result property="goods.discount" column="discount"></result>
<result property="goods.isFreeDelivery" column="is_free_delivery"></result>
<result property="goods.categoryId" column="category_id"></result>
<result property="category.categoryId" column="category_id"></result>
<result property="category.categoryName" column="category_name"></result>
<result property="category.parentId" column="parent_id"></result>
<result property="category.categoryLevel" column="category_level"></result>
<result property="category.categoryOrder" column="category_order"></result>
<result property="test" column="test"/>
</resultMap>
<select id="selectGoodsDTO" resultMap="rmGoods">
select g.* , c.*,'1' as test from t_goods g , t_category c
where g.category_id = c.category_id
</select>
-test
/**
* 利用ResultMap进行结果映射
* @throws Exception
*/
@Test
public void testSelectGoodsDTO() throws Exception {
SqlSession session = null;
try{
session = MyBatisUtils.openSession();
List<GoodsDTO> list = session.selectList("goods.selectGoodsDTO");
for (GoodsDTO g : list) {
System.out.println(g.getGoods().getTitle());
}
}catch (Exception e){
throw e;
}finally {
MyBatisUtils.closeSession(session);
}
}
- 查询结果
4-4 选择练习
esultMap中对应数据库的字段的属性应该是column
第5章 MyBatis的数据插入、修改与删除
5-1 MyBatis数据插入操作
- 当事务中所有的操作都成功后,才发起commit操作,一次性写入数据库。
- Good.xml
<insert id="insert" parameterType="com.imooc.mybatis.entity.Goods" flushCache="true">
INSERT INTO t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery, category_id)
VALUES (#{title} , #{subTitle} , #{originalCost}, #{currentPrice}, #{discount}, #{isFreeDelivery}, #{categoryId})
<selectKey resultType="Integer" keyProperty="goodsId" order="AFTER">
select last_insert_id()
</selectKey>
</insert>
- test
/**
* 新增数据
* @throws Exception
*/
@Test
public void testInsert() throws Exception {
SqlSession session = null;
try{
session = MyBatisUtils.openSession();
Goods goods = new Goods();
goods.setTitle("测试商品");
goods.setSubTitle("测试子标题");
goods.setOriginalCost(200f);
goods.setCurrentPrice(100f);
goods.setDiscount(0.5f);
goods.setIsFreeDelivery(1);
goods.setCategoryId(43);
//insert()方法返回值代表本次成功插入的记录总数
int num = session.insert("goods.insert", goods);
session.commit();//提交事务数据
System.out.println(goods.getGoodsId());
}catch (Exception e){
if(session != null){
session.rollback();//回滚事务
}
throw e;
}finally {
MyBatisUtils.closeSession(session);
}
}
5-3 selectKey与useGeneratedKeys的区别
5-4 更新与删除操作
<!--id名 自己定义-->
<update id="update" parameterType="com.imooc.mybatis.entity.Goods">
UPDATE t_goods
SET
title = #{title} ,
sub_title = #{subTitle} ,
original_cost = #{originalCost} ,
current_price = #{currentPrice} ,
discount = #{discount} ,
is_free_delivery = #{isFreeDelivery} ,
category_id = #{categoryId}
WHERE
goods_id = #{goodsId}
</update>
<!--delete from t_goods where goods_id in (1920,1921)-->
<delete id="delete" parameterType="Integer">
delete from t_goods where goods_id = #{value}
</delete>
- test
/**
* 更新数据
* @throws Exception
*/
@Test
public void testUpdate() throws Exception {
SqlSession session = null;
try{
session = MyBatisUtils.openSession();
//先使用主键获取原始数据
Goods goods = session.selectOne("goods.selectById", 739);
//再根据需求修改
goods.setTitle("更新测试商品");
int num = session.update("goods.update" , goods);
session.commit();//提交事务数据
}catch (Exception e){
if(session != null){
session.rollback();//回滚事务
}
throw e;
}finally {
MyBatisUtils.closeSession(session);
}
}
/**
* 删除数据
* @throws Exception
*/
@Test
public void testDelete() throws Exception {
SqlSession session = null;
try{
session = MyBatisUtils.openSession();
//739为删除数据的主键
int num = session.delete("goods.delete" , 739);
session.commit();//提交事务数据
}catch (Exception e){
if(session != null){
session.rollback();//回滚事务
}
throw e;
}finally {
MyBatisUtils.closeSession(session);
}
}
第6章 预防SQL注入攻击
6-1 预防SQL注入攻击
开发中一般使用#{}