MyBatis入门笔记

MyBatis入门

一、概述

MyBaits是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架;

jdbc缺陷:存在大量的硬编码灵活性低,大量的无关业务的处理编码,如连接和关闭数据库的操作,扩展优化不便;

优点:
1、避免传统JDBC硬编码,执行高效,是JDBC的延伸 2、使用XML将SQL与程序解耦,便于维护
3、POJO对象和数据库记录直接映射 4、完善的文档支持

应用场景:1.更加关注SQL优化的项目;2.需求频繁改动的项目

二、框架概念

框架是一种规则,保证开发者遵循相同的方式开发程序,框架提倡”不要重复造轮子”,对基础功能进行封装,极大提高了开发效率,统一的编码规则,利于团队管理和维护。

SSM开发框架:

  • Spring:对象容器框架,对各个对象有效管理,底层框架;
  • Spring MVC:替代Servlet,帮助我们更好的在web层面进行开发;
  • MyBaties:简化数据库的交互,底层把JDBC进行了封装;

三、MyBatis开发流程

新建数据库连接时,注意加上时区测试

useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC

比如连接icake数据库的URL

jdbc:mysql://localhost:3306/icake?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
  1. 引入MyBatis依赖,利用maven进行管理

    pom.xml中加入阿里云的仓库连接,下载依赖包更稳更快

    <repositories>
        <repository>
            <id>aliyun</id>
            <name>aliyun</name>
            <url>https://maven.aliyun.com/repository/public</url>
        </repository>
    </repositories>
    
  2. 创建核心配置文件,使用xml文件配置。

    比如:配置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>
        <environments default="dev">
            <environment id="dev">
                <transactionManager type="JDBC"></transactionManager>
                ...
    
  3. 创建实体(Entity)类,设置属性,生成get、set方法

    public class Goods {
        private Integer goodsId;//商品编号
        private String title;//标题
        ...
        public Integer getGoodsId() {
            return goodsId;
        }
        ...
    }
    
  4. 创建Mapper映射文件,实体类和数据表的映射

    <?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语句-->
    <!-- resultType结果类型时Goods对象,每一条记录都被包装成Goods对象-->
    <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> 
    
  5. 初始化SessionFactory,会话工厂。读取配置文件。比如读取mybatis-config.xml

    //初始化工具类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);
                ...
    public static SqlSession openSession(){
        //默认SqlSession对自动提交事务数据(commit),设置false代表关闭自动提交,改为手动提交事务数据
        return sqlSessionFactory.openSession(false);
    }   
    
  6. 利用SqlSession对象操作数据,增,删,改,查。

    //新建测试类MyBatisTestor,创建testSelectAll方法,编写java代码对数据库进行操作
    public void testSelectAll() throws Exception {
        SqlSession session = null;
        try{
            session = MyBatisUtils.openSession();
            //goods.selectAll定位sql语句,返回的是一堆Goods对象,用list集合来存放
            //session.selectList返回多条数据,session.selectOne()方法返回一条数据
            List<Goods> list = session.selectList("goods.selectAll");
            //for循环,getTitle()方法,输出对应表的标题
            for(Goods g : list){
                System.out.println(g.getTitle());
            }
        }catch (Exception e){
            throw e;
        }finally {
            MyBatisUtils.closeSession(session);
        }
    }
    
    

四、环境配置

mybatis-config.xml文件

MyBatis采用XML格式配置数据库环境信息,MyBaits环境配置标签,environment包含数据库驱动、URL、用户名与密码,, 。idea内置了连接数据库的方法。

例子:<!--配置环境,不同的环境不同的id名字-->
<environment id="dev">
<!--采用JDBC方式对数据库事务进行commit/rollback-->
<transactionManager type="JDBC"></transactionManager>
<!--采用连接池方式管理数据库连接-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>

五、MyBatis的核心对象

SqlSessionFactory

SqlSessionFactory是MyBatis的核心对象,用于加载配置文件,初始化MyBatis框架,创建SqlSession对象,保证SqlSessionFactory在应用中全局唯一

SqlSession

SqlSession是MyBatis操作数据库的核心对象,SqlSession使用JDBC方式与数据库交互,SqlSession对象提供了数据表CRUD对应方法,CURD是创建(Create)、更新(Update)、读取(Retrieve)和删除(Delete)操作。

初始化工具类MyBatisUtils,在工具类中配置,保证SqlSessionFactory在应用中全局唯一

/**
 * 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();
            throw new ExceptionInInitializerError(e);
            //初始化错误时,通过抛出异常ExceptionInInitializerError通知调用者
        }
    }
    /**
     * 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();
        }
    }
}

六、MyBatis数据查询

数据查询步骤

  • 创建实体类(Entity),类中的属性是根据数据表的字段创建的

  • 创建Mapper XML

    作用:说明创建的类中的属性和数据库中表的对应关系,说明了对象和表之间的映射关系。mapper文件中存放了要执行的sql语句

    注意:xml文件最上面,加上xml声明和mybatis的dtd声明,dtd是约束文件,在dtd中定义对xml文件的约束,这样可以保证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">

  • 要在mybatis-config.xml文件中声明mapper
    <mappers>
        <mapper resource="mappers/goods.xml"/>
    </mappers>

  • 编写SQL标签,编写要执行的sql语句
<!-- 不同的namespace用来区分不同的sql语句-->
<!-- resultType结果类型时Goods对象,每一条记录都被包装成Goods对象-->
<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>

  • 开启驼峰命名映射:比如:数据库表的某一字段名为:goods_id,创建类的对象属性为:goodsId(驼峰命名法)。名字不对应导致查询不到数据库中的数据。开启驼峰命名映射后,会把goods_id映射为goodsId

    在mybatis-config.xml文件中配置驼峰命名映射

<settings>
        <!-- goods_id ==> goodsId 驼峰命名转换 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
 </settings>

  • SqlSession执行select语句

SQL传参

单参数传递,使用parameterType指定参数的数据类型即可,SQL中#{value}提取参数

1.mapper映射文件中配置映射:
<select id="selectById" parameterType="Integer"
resultType="com.imooc.mybatis.entity.Goods">
	select * from t_goods where goods_id = #{value}
</select>

2.对应的java调用代码:
SqlSession session = MyBatisUtils.openSession();
//session.selectOne()方法返回一条数据
Goods goods = session.selectOne("goods.selectById",1602);
//getTitle()方法,输出对应表的标题
System.out.println(goods.getTitle());

多参数传递,使用parameterType指定Map接口,SQL中#{key}提取参数。parameterType=“java.util.Map”

注意:若映射文件中,SQL语句对应的id是全局唯一的,调用时也可以不写命名空间

Map的妙用

Map的适用场景:为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>

//java中的调用代码:
SqlSession session = MyBatisUtils.openSession();
Map param = new HashMap();
param.put("min", 100);
param.put("max", 500);
param.put("limt", 10);
//selectByPriceRange前面可以不加goods这个namespace,前提是保证你这个sql全局唯一
List<Goods> list = session.selectList("selectByPriceRange", param);
for (Goods goods:list) {
    System.out.println(goods.getTitle() + ": " + goods.getCurrentPrice());
}

查询返结果包含跨表字段

<select id="findGoodsMap" resultType="java.util.LinkedHashMap">
    select g.* , c.category_name
    from t_goods g , t_category c
    where g.category_id = c.category_id
</select>

session = MyBatisUtils.openSession();
//session.selectList返回多条数据,session.selectOne()方法返回一条数据
//list集合中存放的是Map类型的数据,即存放的是键值对类型的数据
List<Map> list = session.selectList("goods.selectGoodsMap");
for (Map map : list) {
    System.out.println(map);
}

利用LinkedHashMap保存多表关联结果,当resultType为Map时,查询出来的数据是无序的。

MyBatis会将每一条记录包装为LinkedHashMap,键-值对象

key是字段名 value是字段对应的值 , 字段类型根据表结构进行自动判断

优点: 易于扩展,易于使用

缺点: 太过灵活,无法进行编译时检查

ResultMap结果映射

goods.xml文件配置ResultMap结果映射

/**
 * Goods类的扩展,DTO,即数据传输对象,用来将sql查询结果映射为Java对象,GoodsDTO承载了多表关联查询的结果
 * 所有在sql中出现的字段,都可以在这里找到对应的属性
 */
public class GoodsDTO {
    //Goods goods = new Goods(),实例化一个对象,goods即有了在Goods里面创建的许多属性和方法
    private Goods goods = new Goods();
    private Category category = new Category();
    private String test;
    public Goods getGoods() {
        return goods;
    	...  
    }

<!--结果映射的id值来自select标签resultMap,type类型是要映射的java对象-->
<resultMap id="rmGoods" type="com.imooc.mybatis.dto.GoodsDTO">
    <!--resultMap中有id标签和result标签,property是类的属性,column是主键字段
    id标签,即主键标签,用来设置主键字段和类属性的映射。
    result标签,用来设置除了主键以外的其他字段
    -->
    <!--设置主键字段与属性映射-->
    <id property="goods.goodsId" column="goods_id"></id>
    <result property="goods.title" column="title"></result>
    ...
    <result property="category.categoryId" column="category_id"></result>
    <result property="category.categoryName" column="category_name"></result>
    ...
</resultMap>
<select id="selectGoodsDTO" resultMap="rmGoods">
    select g.* , c.* from t_goods g , t_category c
    where g.category_id = c.category_id
</select>

session = MyBatisUtils.openSession();
//session.selectList返回多条数据,session.selectOne()方法返回一条数据
List<GoodsDTO> list = session.selectList("goods.selectGoodsDTO");
for (GoodsDTO g: list) {
    System.out.println(g.getGoods().getTitle());
}

作用:ResultMap可以将复杂的查询结果映射为JavaDTO对象,可以轻松的获取到属性,不像map一样容易出错,缺点就是需要额外的设置映射规则

ResultMap常用于保存多表关联结果,是Map对象的替代,Map拥有更好扩展性,ResultMap则拥有更好的可读性

多人协作的时候是有必要的,小项目可以使用map

七、MyBatis数据写入

数据库事务是保证数据操作完整性的基础,MySQL workbench等客户端编写sql语句,执行后,成为事务日志,事务日志通过commit命令再提交到数据库表中

在这里插入图片描述

三种写操作

插入 -

<!--新增数据,#{title}自动提取来自Goods实体类中设置好的title属性值-->
<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})
    <!-- 当前连接中最后产生的id号,获取后添加到Goods对象goodsId属性中 -->
    <selectKey resultType="Integer" keyProperty="goodsId" order="AFTER">
    select last_insert_id()
    </selectKey>
</insert>

SqlSession session = MyBatisUtils.openSession();
Goods goods = new Goods();
//这里没有设置id,在goods.xml文件中通过selectKey标签自动添加到goodsId
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);
//执行插入数据后,还要通过commit把新增数据的事务日志提交到数据库表中
session.commit();

注意:catch块中加上回滚
//commit提交后,数据库事务日志会清空,如果不为空,则说明异常,需要回滚,从新写入事务日志,再提交数据库
if (session != null) {
    session.rollback();
}

注意:sqlSessionFactory.openSession(false);默认SqlSession对自动提交事务数据(commit),设置false代表关闭自动提交,改为手动提交事务数据

更新 -

<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>

session = MyBatisUtils.openSession();
//先获取739id对应的一条数据,返回的是一个goods对象
Goods goods = session.selectOne("goods.selectById", 739);
//修改id为739的标题
goods.setTitle("测试标题");
//执行更新sql语句,把修改好的goods对象数据传入到数据表中
int num = session.update("goods.update", goods);
//执行更新数据后,还要通过commit把新增数据的事务日志提交到数据库表中
session.commit();

删除 -

<delete id="delete" parameterType="Integer">
    delete from t_goods where goods_id = #{value}
</delete>

//执行delete操作,删除id为739的那一条数据
int num = session.delete("goods.delete", 739);
//执行更新数据后,还要通过commit把新增数据的事务日志提交到数据库表中
session.commit();

八、MyBatis预防SQL注入攻击

SQL注入攻击是指攻击者利用SQL语句,导致输入的变成了sql语句的一部分

MyBatis两种传值方式

  • ${ }文本替换,直接替换,未经任何转移,直接对SQL文本替换,会产生注入攻击风险,不推荐使用
  • #{ }预编译传值,把输入的整体变成了一个字符串,使用预编译传值可以预防SQL注入
<select id="selectByTitle" parameterType="java.util.Map" resultType="com.imooc.mybatis.entity.Goods">
    select * from t_goods where title = #{title}
    ${order}
</select>

session = MyBatisUtils.openSession();
Map param = new HashMap();
/*
    ${}原文传值
    select * from t_goods
    where title = '' or 1 =1 or title = '【德国】爱他美婴幼儿配方奶粉1段800g*2罐 铂金版'
*/
/*
   #{}预编译
   select * from t_goods
    where title = "'' or 1 =1 or title = '【德国】爱他美婴幼儿配方奶粉1段800g*2罐 铂金版'"
*/

param.put("title","'' or 1=1 or title='【德国】爱他美婴幼儿配方奶粉1段800g*2罐 铂金版'");
param.put("order" , " order by title desc");
List<Goods> list = session.selectList("goods.selectByTitle", param);
for(Goods g:list){
    System.out.println(g.getTitle() + ":" + g.getCurrentPrice());
}

九、MyBatis工作流程

工作流程:mybatis-config.xml—SqlSessionFactory—SqlSession—执行配置好的SQL —SessionClose
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值