MyBatis学习

一、mybatis是什么

  • MyBatis是一个ORM的数据库持久化框架
    框架(Framework)是一个框子——指其约束性,也是一个架子——指其支撑性,框架本身不解决问题。
  • 什么叫数据库持久化:
    数据库持久化是数据持久化的其中一种,就是把内存中的数据保存到数据库中。
  • Java中最简单的就是使用jdbc来完成数据库持久化:但是代码重复,拼接复杂。。
    在这里插入图片描述
  • ORM框架映射方式?
    1、Sql操作方式(对jdbc进行封装):
    把SQL配置到配置文件中,通过不同SQL中完成对象实体和数据库关系相互转换的操作。(mybatis的实现方式)
    2、完整操作:
    直接映射的是对象实体和数据库关系映射。操作数据库关系,不用写SQL有框架自己生成。(JPA、Hibenate实现方式)
    mybatis的取别在于是通过映射sql(不完全映射)来操作数据库

二、准备jar包,实体类

  • 新建普通Java项目
  • 数据库准备一张表product
    创建实体类
public class Product {
	private	Long id;
	//商品名称
	private String productName;
	//品牌
	private String brand;
	//供应商
	private String supplier;
	//零售价
	private BigDecimal salePrice;
	//进价
	private BigDecimal costPrice;
	//折扣价
	private Double cutoff;
	//商品分类编号
	private Long dir_id;
	 
   //提供getter与setter...
}
  • 准备 dao层
public interface IProductDao {

    void save(Product product);

    void remove(Long id);

    void update(Product product);

    Product loadOne(Long id);

    List<Product> loadAll();
}

三、搭建环境

在这里插入图片描述

  • 新建lib文件夹
  • recourses文件夹
  • 导入相应的jar包
    在这里插入图片描述
  • recourses中新建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="db.properties"></properties>
    <!--给类取别名   在映射关系中可以直接使用别名表示-->
    <typeAliases>
       <!-- 细节,注意路径是斜杠,实体是点-->
        <typeAlias type="com.lr.mybatis._03_using_detail.domain.Product" alias="Product" />
        <!-- 包的配置:项目,添加了包之后,类名就是别名!!!! -->
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${db.driver}"/>
                <property name="url" value="${db.url}"/>
                <property name="username" value="${db.username}"/>
                <property name="password" value="${db.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--加载实体映射的xml文件-->
    <!--通过一个个数据库与实体的关系映射中的sql语句来操作数据库-->
   <mappers>
       <!--切换关系映射的时候一定要注释掉之前的!-->
        <!--<mapper resource="com/lr/mybatis/_01_hello/domain/Productmapper.xml"/>-->
       <!--抽取工具的版本-->
        <!--<mapper resource="com/lr/mybatis/_02_mybatis_util/domain/Productmapper.xml"/>-->
       <!--<mapper resource="com/lr/mybatis/_03_using_detail/domain/Productmapper.xml"/>-->
       <mapper resource="com/lr/mybatis/_04_batch_many/domain/Productmapper.xml"/>
    </mappers>

</configuration>
  • recourses中新建db.properties
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql:///mybatistest
db.username=xxx
db.password=xxxxx
  • 在实体类中新建xx类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">
<!--映射文件根
    namespace:命名空间
        1 相当于java包,配置sqlid进行唯一区分sql:namespace+sqlId
        2 规范:domain全限定名+Mapper:拷贝以免出错
-->
<!--实现方法的时候,session传入的是命名空间加上,命名空间的方法名字  区分其他关系映射-->
<mapper namespace="com.lr.mybatis._02_mybatis_util.domain.ProductMapper">
    <!--
     sql语句
        id:配合namesapce唯一确定sql,名称和方法名一致
        parameterType:参数类型
         resultType:返回值类型
         -->
    <select id="loadOne" parameterType="long" resultType="Product">
        select * from product where id = #{id}
    </select>
    <!--List<Product> loadAll();
      resultType:如果返回值是集合,那返回类型不是集合,是集合里面内容类型
    -->
    <select id="loadAll" resultType="com.lr.mybatis._02_mybatis_util.domain.Product">

        SELECT * FROM product

    </select>
    <!--void save(Product product);-->
    <!--select和insert不影响,主要是看里面的语句-->
    <insert id="save" parameterType="com.lr.mybatis._02_mybatis_util.domain.Product" >

        INSERT INTO product (productName,brand,supplier,salePrice,costPrice,cutoff,dir_id) VALUES (
        #{productName},
        #{brand},
        #{supplier},
        #{salePrice},
        #{costPrice},
        #{cutoff},
        #{dir_id})

    </insert>
    <!--void remove(Long id);-->
    <delete id="remove" parameterType="long" >

        DELETE FROM product WHERE id = #{id}

    </delete>
    
    <!--void update(Product product);-->
    <update id="update" parameterType="com.lr.mybatis._02_mybatis_util.domain.Product" >

        update product set
         productName = #{productName},
         brand = #{brand},
         supplier = #{supplier},
         salePrice = #{salePrice},
         costPrice = #{costPrice},
         cutoff = #{cutoff},
         dir_id = #{dir_id}
        where id = #{id}

    </update>
    
</mapper>
  • 在MyBatis-Config.xml中引入关系映射xml
  • <mappers> <!--切换关系映射的时候一定要注释掉之前的!--> <!--<mapper resource="com/lr/mybatis/_02_mybatis_util/domain/Productmapper.xml"/>--> </mappers>

小结:
配置MyBatis-Config.xml
引入关系映射xml,关系映射文件中的sql决定了功能
映射文件要取命名空间,方便区分使用
映射文件中的sql方法取id,实现的时候调用这个id就可以
注意 sql中的配置
注意配置文件中的文件路径和实体路径,如果是文件的地址,是斜杠划分
实体类是.划分
实现方法的时候,是使用的命名空间的命名加上方法id
MyBatis-Config.xml引入的是xml映射关系文件

四、impl层实现

  • 读取配置文件
  • SqlSessionFactory获取
  • 获取SqlSession对象

问题:
每次实现方法都需要创建,获取,关闭。。

 @Override
    public void save(Product product) {
        SqlSession sqlSession = null;
        try {
            //加载mybatis.xml文件
            Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
            //获取session工厂对象
            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
            //测试工厂对象是否加载成功
            System.out.println(sessionFactory);
            //拿到session
            sqlSession = sessionFactory.openSession();
            //返回集合selectList
            sqlSession.insert("com.lr.mybatis._01_hello.domain.ProductMapper.save",product);
            sqlSession.commit();
        }catch (Exception e){
            sqlSession.rollback();
            e.printStackTrace();
        }finally {
            //关闭session
            if (sqlSession!=null){
                sqlSession.close();
            }
        }
    }

入门小结

  1. 准备配置文件-Mybatis-Config.xml
    1)环境配置-配置怎么访问数据
    2)导入映射配置-先不配置
  2. 基于配置文件创建SqlSessionFactory
    1)通过配置文件获取Reader
    2)SqlSessionFactoryBuilder.build(reader)
  3. 通过SqlSessionFactory获取SqlSession,并调用对应的api完成对应操作
    1)配置映射文件并且在Mybatis-Config.xml导入
    2)获取SqlSession
    3)调用api-selectOne,selectList,insert,delete,update
    4)如果是增删改要做事务控制 commit rollback
    5)关闭sqlsession

五、工具类抽取

为了减少重复代码,抽取一个工具类,可以方便的获取session对象和关闭对象

public enum  MybatisUtil {
    INSTANCE;
    //获取session的工厂
    private static SqlSessionFactory sessionFactory;
    //静态代码块,运行就创建
    //在其他地方可以随时调用获取session
    static {
        //加载工厂对象
        //加载mybatis.xml文件
        try {
            //注意try catch中如果先没有处理异常,会报错
            Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
            //获取session工厂对象
            sessionFactory = new SqlSessionFactoryBuilder().build(reader);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    //得到sqlsession的方法
    public SqlSession openSqlSession (){
        //System.out.println("================");
        SqlSession sqlSession = sessionFactory.openSession();
        //System.out.println("+++++++++++++++++++++++");
        return sqlSession;
    }
    //关闭 SqlSession 的方法  需要传入sqlSession   确定要关闭的对象是哪一个
    public void endSqlSession(SqlSession sqlSession){
        if (sqlSession!=null){
            sqlSession.close();
        }
    }
}

  • 注意枚举的单例模式
  • 静态代码块
  • 异常处理
  • 将方法中的重复代码全部替换掉

六、mybatis使用一些细节

  1. 保存时返回id
  • 如果没有在关系映射xml中配置时如果马上打印使用这个被添加的对象时,id是空的
  • Product{id=null, productName=‘测试’, brand=‘null’, supplier=‘null’, salePrice=null, costPrice=null, cutoff=null, dir_id=null}只添加了一个名字,但是id是空的
  • mybatis不像jpa,没有自动维护关联表关系的功能所以需要得到返回的id,自动将id设置到刚才添加的对象中,并且我们能使用设置到中间表,手动维护关系
  • 解决方法:
    在映射关系xml中的sql方法配置时,加上这些设置
<!--添加时 useGeneratedKeys是否返回id
    keyProperty  返回的数据的类型
    keyColumn  返回的是什么
    -->
    <insert id="save" parameterType="com.lr.mybatis._03_using_detail.domain.Product"
        keyColumn="id"
        keyProperty="id"
        useGeneratedKeys="true"
    >
  1. 别名
    在MyBatis.xml中配置别名,实体关系映射xml中就可以直接使用别名
    比如
<select id="loadAll" resultType="Product">

        SELECT * FROM product

    </select>

配置的方法

<configuration>
    <!--加载数据库资源文件-->
    <properties resource="db.properties"></properties>
    <!--给类取别名   在映射关系中可以直接使用别名表示-->
    <typeAliases>
       <!-- 细节,注意路径是斜杠,实体是点-->
        <typeAlias type="com.lr.mybatis._03_using_detail.domain.Product" alias="Product" />
        <!-- 包的配置:项目,添加了包之后,类名就是别名!!!! -->
    </typeAliases>
</configuration>
  1. 日志支持
    log4j-1.2.17.jar
    slf4j-api-1.7.2.jar
    slf4j-log4j12-1.7.2.jar
    在资源文件中配置log4j.properties
    在这里插入图片描述
log4j.rootLogger=DEBUG, stdout
#log4j.rootLogger=NONE
log4j.logger.com.lr=TRACE

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n

一定要根据自己的包名情况进行修改
如果配置成功,那么在MyBatis运行操作数据时就可以看到相应的日志了。
如果要打印到debug,需要改成
log4j.rootLogger=DEBUG, stdout

  1. #与$区别
  • #{OGNL表达式}
MyBatis会把这个表达式使用?(占位符)替换,作为一个sql参数使用:推荐使用
     比如name的值为:  
     定义SQL: select * from t_user where name = #{name}
     最终SQL: select * from t_user where name = ? 
  • ${OGNL表达式} 的区别

MyBatis会把这个表达式的值替换到sql中,作为sql的组成部分;
该方式主要用于程序拼接SQL;
如果sql中使用${OGNL},并且参数的类型是(integer,string…)那么OGNL表达式可以写成任意东西;

  • ${OGNL}表达式的应用场景
    1)不能用在登录,会出现sql注入
    比如登录功能,在输入name的时候可以人为的制造成功:
User user=new User();
user.setName("\"admin\" or \"1=1\" ");
user.setPassword("\"admin\"  ");
     定义SQL: select id,name,password from t_user where name = ${name} and password=${password}
     最终SQL: select id,name,password from t_user where name="test" or "1=1" and password="test"  出现sql注入

2)用在order by + limit的场景

七、常用的动态SQL

  1. 传入id批量删除
<!-- delete from product where id in ( ? , ? ) 批量删除: 
collection="list":传入的list,相当于map的key,通过list得到传入的整个集合的值; 
		index="index" :每次循环的索引
 item="id" :每次循环的这个值 
open="(" :以什么开始 
separator=",":分隔符 
		close=")":以什么结束 
-->
<delete id="removeMany" parameterType="java.util.ArrayList" >
        DELETE FROM product WHERE id IN <foreach collection="list"
         open="(" close=")"
         separator="," item="id">
          #{id}
    </foreach>
    </delete>

实现方法

@Override
    public void removeMany(List<Long> ids) {
        System.out.println("=======================");
        SqlSession sqlSession =null;
        try {
            sqlSession = MybatisUtil.INSTANCE.openSqlSession();
            sqlSession.delete("com.lr.mybatis._04_batch_many.domain.ProductMapper.removeMany", ids);
            //提交事务
            sqlSession.commit();
        }catch (Exception e){
            //事务回滚
            sqlSession.rollback();
            e.printStackTrace();
        }finally {
            MybatisUtil.INSTANCE.endSqlSession(sqlSession);
        }
    }
  1. 批量添加
<!-- 批量插入: 
	 insert into product(productName,salePrice,costPrice,cutoff,supplier,brand,dir_id) 
		values (?,?,?,?,?,?,?) , (?,?,?,?,?,?,?) 
	   parameterType:传入参数是:java.util.List的类型的; 
	           对传入的list进行foreach循环:取出值填入插入的values中: 
		collection="list":这个不能修改,表示传入的一个list类似于一个key是list,得到传入的list集合
	    index="index":每一次遍历的序号 
		item="item":每次遍历的这个对象别名,可以修改 
		separator=",":每遍历一次后的分隔符
		-->
		<insert id="addMany" parameterType="java.util.ArrayList" >

        INSERT  INTO product (productName,brand,supplier,salePrice,costPrice,cutoff,dir_id)VALUES
        <foreach collection="list" item="product" separator=",">
        (#{product.productName},#{product.brand},#{product.supplier},#{product.salePrice},
        #{product.costPrice},#{product.cutoff},#{product.dir_id})

        </foreach>
    </insert>

实现方法

@Override
    public void addMany(List list) {
        SqlSession sqlSession =null;
        try {
            sqlSession = MybatisUtil.INSTANCE.openSqlSession();
            sqlSession.delete("com.lr.mybatis._04_batch_many.domain.ProductMapper.addMany", list);
            //提交事务
            sqlSession.commit();
        }catch (Exception e){
            //事务回滚
            sqlSession.rollback();
            e.printStackTrace();
        }finally {
            MybatisUtil.INSTANCE.endSqlSession(sqlSession);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值