文章目录
MyBatis入门
一、框架的作用
框架是可被应用开发者定制的应用骨架。
框架是一种规则,保证开发者遵循相同的方式开发程序。
框架提倡“不要重复造轮子”,对基础功能进行封装。
1、框架的优点
极大提升了开发效率。
统一的编码规则,利于团队管理。
灵活配置的应用,拥有更好的维护性。
二、什么是MyBatis
MyBatis是优秀的持久层框架。
MyBatis使用XML将SQL与程序解耦,便于维护。
MyBatis学习简单,执行高效,是JDBC的延伸。
官方中文文档:
https://mybatis.org/mybatis-3/zh/
1、MyBatis开发流程
引入MyBatis依赖
创建核心配置文件
创建实体(Entity)类
创建Mapper映射文件
初始化SessionFactory
利用SqlSession对象操作数据
三、Mybatis环境配置
1、引入MyBatis依赖
在pom.xml文件中
...
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
...
2、mybatis-config.xml
MyBatis采用XML格式配置数据库环境信息。
MyBatis环境配置标签。
environment包含数据库驱动、URL、用户名与密码。
<?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="dev">
<!--配置环境,不同的环境不用的id名称-->
<environment id="dev">
<!--采用JDBC方式对数据库事务进行commit/rollback-->
<transactionManager type="JDBC"/>
<!--采用连接池方式管理数据库连接-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/databaseName?useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
<environment id="prd">
<!--采用JDBC方式对数据库事务进行commit/rollback-->
<transactionManager type="JDBC"/>
<!--采用连接池方式管理数据库连接-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.1.34:3306/databaseName?useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
四、SqlSessionFactory
SqlSessionFactory是MyBatis的核心对象
用于初始化MyBatis,创建SqlSession对象。
保证SqlSessionFactory在应用中全局唯一。
1、SqlSession
SqlSession是MyBatis操作数据库的核心对象。
SqlSession使用JDBC方式与数据库交互。
SqlSession对象提供了数据表CRUD对应方法。
...
//利用Reader加载classpath下的mybatis-config.xml核心配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//初始化SqlSessionFactory对象,同时解析mybatis-config.xml文件
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//创建SqlSession对象,SqlSession是JDBC的扩展类,用于与数据库交互
SqlSession sqlSession = null;
try{
sqlSessionFactory.openSession();
//创建数据库连接(测试用)
Connection connection = sqlSession.getConnection();
}catch(Exception e){
e.printStackTrace();
}finally{
if(sqlSession!=null){
//如果type="POOLED",代表使用连接池,close则是将连接回收到连接池中
//如果type="UNPOOLED",代表直连,close则会调用Connection.close()方法关闭连接
sqlSession.close();
}
}
...
五、初始化工具类MyBatisUtils
为了保证SqlSessionFactory在应用中全局唯一,把初始化SqlSessionFactory对象的代码写在工具类中。
//NyBatisUtils工具类,创建全局唯一的SqlSessionFactory对象
public class NyBatisUtils{
//利用static(静态)属于类不属于对象,且全局唯一
public 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对象
public static SqlSession openSession(){
return sqlSessionFactory.openSession();
}
//释放一个有效的SqlSession对象
public static void closeSession(SqlSession session){
if(sqlSession!=null){
//如果type="POOLED",代表使用连接池,close则是将连接回收到连接池中
//如果type="UNPOOLED",代表直连,close则会调用Connection.close()方法关闭连接
sqlSession.close();
}
}
}
六、MyBatis数据查询
1、MyBatis数据查询步骤
创建实体类(Entity)
创建Mapper XML
编写SQL标签
开启驼峰命名映射
新增
SqlSession执行select语句
2、创建实体类(Entity)
public class Goods{
private Integer goodsId;
private String title;
...
public Integer getGoodsId(){
return goodsId;
}
public void setGoodsId(Integer goodsId){
this.goodsId = goodsId;
}
...
}
3、创建Mapper XML并编写SQL标签
在resources/mappers目录下创建goods.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">
<!--namespace命名空间,为了区分不同表的sql语句-->
<mapper namespace="goods">
<!--id属性在同一个命名空间下值唯一-->
<!--resultType返回类型,会把每一条记录包装成指定的类型-->
<select id="selectAll" resultType="com.ql.mybatis.entity.Goods">
select * from t_goods order by goods_id desc limit 10
</select>
</mapper>
4、在mybatis-config.xml配置文件中添加并开启驼峰命名映射
<configuration>
<settings>
<!--goods_id ==> goodsId 驼峰命名转换-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
...
<!--在configuration标签里添加-->
<mappers>
<mapper resource="mappers/goods.xml">
</mappers>
</configuration>
5、SqlSession执行select语句
SqlSession session = null;
try{
session = MyBatisUtils.openSession();
List<Goods> list = session.selectList("goods.selectAll");
}catch(Exception e){
throw e;
}finally{
MyBatisUtils.closeSession(session);
}
七、SQL传参
1、传递单参数:
Goods goods = session.selectOne("goods.selectById",1602);
2、传递多条参数时:
<select id="selectByPriceRange" parameterType="java.util.Map" resultType="com.ql.mybatis.entity.Goods">
select * from t_goods
where
current_price between #{min} and #{max}
order by current_price
limit 0,#{limt}
</select>
Map param = new HashMap();
param.put("min",100);
param.put("max",500);
param.put("limt",10);
//不加namespace前缀时保证id全局唯一
List<Goods> list = session.selectList("selectByPriceRange",param);
八、MyBatis获取多表关联查询结果
多表关联时resultType可以是Map(HashMap),但是结果没有顺序,建议使用LinkedHashMap,会按照数据库表字段顺序返回结果。
<!--利用LinkedHashMap保存多表关联结果
MyBatis会将每一条记录包装为LinkedHashMap对象
key是字段名 value是字段对应的值,字段类型根据表结构进行自动判断
优点:易于扩展,易于使用
缺点:太过灵活,无法进行编译时检查
-->
<select id="selectCoodsMap" resultType="java.util.LinkedHashMap">
select g.* , c.category_name from t_goods g, t_category c
where g.category_id = c.category_id
</select>
查询时返回Map的集合
List<Map> list = session.selectList("goods.selectGoodsMap");
九、ResultMap结果映射
ResultMap可以将查询结果映射为复杂类型的Java对象。
ResultMap适用于Java对象保存多表关联结果。
ResultMap支持对象关联查询等高级特性。
首先,创建结果映射对象:
//Data Transfer Object--数据传输对象
public class GoodsDTO{
private Goods goods = new Goods();
private String categoryName;
public Goods getGoods(){
return goods;
}
...
}
<!--结果映射-->
<resultMap id="rmGoods" type="com.ql.mybatis.dto.GoodsDTO">
<!--设置主键字段与属性映射-->
<id property="goods.goodsId" column="goods_id">
<!--设置非主键字段与属性映射-->
<result property="goods.title" column="title"></result>
<result property="goods.categoryId" column="category_id"></result>
<result property="categoryName" column="category_name"></result>
</resultMap>
<select id="selectCoodsDTO" resultMap="rmGoods">
select g.* , c.category_name from t_goods g, t_category c
where g.category_id = c.category_id
</select>
十、MyBatis数据写入
1、数据库事务
数据库事务是保证数据操作完整性的基础。
2、MyBatis写操作包含三种
插入 - <insert>
更新 - <update>
删除 - <delete>
3、插入 - <insert>
last_insert_id() --MySQL函数,用于获取当前连接最后产生的id号,不会有并发问题。
//insert()方法返回值代表本次成功插入的记录总数
int num = session.insert("goods.insert", goods);
session.commit();//提交事务数据
4、selectKey与useGeneratedKeys的区别
selectKey标签用法:
useGeneratedKeys属性用法:
二者区别-显示与隐示
selectKey标签需要明确编写获取最新主键的SQL语句。
useGeneratedKeys属性会自动根据驱动生成对应的SQL语句。
二者区别-应用场景不同
selectKey适用与所有关系型数据库。
useGeneratedKeys只支持“自增主键”类型的数据库。
在Oracle中selectKey的用法
5、更新 - <update>
Goods goods = session.selectOne("goods.selectById", 739);
goods.setTile("更新标题");
int num = session.insert("goods.update", goods);
session.commit();//提交事务数据
6、删除 - <delete>
int num = session.delete("goods.delete", 739);
session.commit();//提交事务数据
十一、MyBatis预防SQL注入攻击
1、SQL注入攻击
SQL注入是指攻击者利用SQL漏洞,绕过系统约束,越权获取数据的攻击方式。
2、MyBatis两种传值方式
${}文本替换,未经过任何处理对SQL文本替换。
#{}预编译传值,使用预编译传值可以预防SQL注入。
/*
${}原文传值
select * from t_goods where title = '' or 1=1
#{}预编译
select * from t_goods where title = "'' or 1=1"
*/
${}原文传值一般可以用到根据不同字段排序(order by)等代码传入的子句,而不能是外界输入的子句。