Mybatis的使用

目录

一,简介

    1.什么是mybatis

二,框架搭建和xml配置

        1.框架搭建

三.实体,接口,和接口的映射文件(规范)

四,#和$的区别

五,封装工具类

六,Mybatis的执行流程

七,传参和手动结果映射

        1.传参

        2.手动结果映射

九,多表查询和动态sql

       1.多表查询

        一对一多表查询(也就是单表查询):association一对一     javaType="一个对象"

        一对多:collection 一对多    ofType=""

                 2.动态sql

十,sql片段,日志,缓存

                2.日志

                日志组件:

                   常见的日志api:

十一,一些常用的配置

                mybatis别名:

十二,延迟加载(懒加载)

十三:缓存(cache)

        缓存失效:

        一级缓存:

        二级缓存:

        二级缓存技术:

十四:数据库连接池(Druid)

十五:逆向工厂(代码生成器)

        MybatisX的使用

十六:注解

        动态Sql:


一,简介

    1.什么是mybatis

            Mybatis是一个半ORM(对象关系映射)的持久层框架,内部封装了JDBC,可以通过xml配置或注解来配置和映射原生信息

二,框架搭建和xml配置

        1.框架搭建

           (1)导入jar包(build libraries)或Maven引入依赖

           (2)创建核心配置类mybatis.xml(mybatis-config.xml)

              事务管理设置:

                       JDBC管理事务

                       MANAGED: mybatis不管事务管理,交给容器(spring)来管理事务

<!--            事务管理器-->
            <transactionManager type="JDBC"></transactionManager>

                数据源设置:POOLED |     UNPOOLED   |     JNDI
                        POOLED :采用数据库连接池,来创建数据库链接。

                        UNPOOLED:不采用数据库连接池。

                        JNDI :在外部配置数据源,然后放置一个 JNDI 上下文的引用,通过名字引入这个外部的数据源

<!--            数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/saima?serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="admin"/>
            </dataSource>

                模板:环境可以配置多个

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

<!--   1、数据库环境-->
    <environments default="mysql8.x">

        <environment id="mysql8.x">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///hscrm?serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>

<!--        <environment id="mysql5.x">-->
<!--            <transactionManager type=""></transactionManager>-->
<!--            <dataSource type=""></dataSource>-->
<!--        </environment>-->

<!--        <environment id="oracle11g">-->
<!--            <transactionManager type=""></transactionManager>-->
<!--            <dataSource type=""></dataSource>-->
<!--        </environment>-->
    </environments>


<!--    2、加载映射文件-->
    <mappers>

    </mappers>

</configuration>

三.实体,接口,和接口的映射文件(规范)

        1.编写实体类  如:Student

        2.编写Mapper接口层(dao)如:StudentMapper或StudentDao

        3..编写映射文件StudentMapper.xml(XML文件用于映射)

                namespace:映射接口的路径

                id:接口的方法名

                resultType:返回的类型

<?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.hs.mapper.CustomerMapper">

    <select id="findAllCustomer" resultType="com.hs.domain.Customer">
        select *  from  customer
    </select>
</mapper>

四,#和$的区别

        #:底层使用的是PeraredStatement,可以使用占位符,避免sql拼接

                如:where password = '123 or 1=1 '

        $:底层使用Statement

五,封装工具类

        创建一个工具类,将重复性的代码封装在一个类中调用

package com.hs.util;

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.InputStream;

public class MyBatisUtil {
    private static SqlSessionFactory   ssf;

    static {
        //        配置文件
        String  fileName="mybatis.xml";
        InputStream in= null;
        try {
            in = Resources.getResourceAsStream(fileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
//        会话工厂(只需构建一次)
        ssf= new SqlSessionFactoryBuilder().build(in);
    }



    public  static  SqlSession    getSqlSession(){
        return   ssf.openSession();
    }

    public static  void    closeSqlSession(SqlSession sqlSession ){
        sqlSession.commit();
        sqlSession.close();
    }

}

六,Mybatis的执行流程

        

七,传参和手动结果映射

        1.传参

                通常把多个参数封装成map或实体
                方法一:通过#{arg0}获取顺序的参数

<select id="findCustomerByNameAndSex"  resultType="com.hs.domain.Customer">
    select  *  from  customer  where   c_name=#{arg0}   and   c_sex=#{arg1}
</select>

                 方法二:通过#{param1}获取顺序的参数

<select id="findCustomerByNameAndSex" resultType="com.hs.domain.Customer">
    select  *  from  customer  where   c_name=#{param1}   and   c_sex=#{param2}
</select>

                方法三:在各个参数前使用@Param("参数名")设置参数的名称

List<Customer>    findCustomerByNameAndSex(@Param("name") String  c_name, @Param("sex") String  c_sex);



<select id="findCustomerByNameAndSex" resultType="com.hs.domain.Customer">
    select  *  from  customer  where   c_name=#{name}   and   c_sex=#{sex}
</select>

        2.手动结果映射

                问题:当表字段与实体属性不一致时如何解决

                方法一:使用sql语句中起别名的方式  as  字段名与实体属性名一致。

                方法二:使用mybatis中的结果集手动映射

    <resultMap id="aaaa" type="映射的实体类">
        <!-- id为主键   -->
        <id property="实体的属性" column="对应的字段"></id>
        <result property="实体的属性" column="字段"></result>
    </resultMap>
    <!--  resultMap对应的是aaaa  -->
    <select id="映射的接口方法名" resultMap="aaaa">
        select * from student
    </select>

九,多表查询和动态sql

       1.多表查询

                表与表之间的关系:

                一对一(一个人只有一张身份证,一个身份证只能对应一个人)

                一对多(一个人可以办理多张银行卡,一张银行卡只能对应一个人)

                多对多(通过中间表,拆为两个一对多)(一个学生可以选择多门课程,一个课程可以由多个学生学习)

        一对一多表查询(也就是单表查询):association一对一     javaType="一个对象"

                方法一:根据表连接的查询结果直接属性与字段对应

public class Student {
    private   int   sid;
    private   String  sname;
    // 一对一 电脑的属性
    private  int  cid;
    private String  cname;

                方法二:将另一个关联的表当作一个属性

public class Computer {
    private  int  cid;
    private String  cname;


public class Student {
    private   int   sid;
    private   String  sname;
    //每个学生对应一个电脑
    private   Computer   computer;


    /**
     * 查询所有学生的姓名和电脑名称
     */
    List<Student> findAllStudent();


<resultMap id="sc" type="com.hs.domain.Student">
        <id  property="sid" column="sid"></id>
        <result property="sname"  column="sname"></result>
        <association property="computer"  column="cid" javaType="com.hs.domain.Computer">
            <id property="cid" column="cid"></id>
            <result property="cname" column="cname"></result>
        </association>
    </resultMap>
    <select id="findAllStudent"  resultMap="sc">
        select  *  from  student s,computer c  where s.cid=c.cid;
    </select>

                方法三:使用mybatis推荐的     

public class Person {
    private int pid;
    private String pname;
//    private int cid; 一对一 身份证
    private IdCard idCard;

public class IdCard {
    private int cid;
    private String cnum;

//IdCard中的查询com.saima.mapper.IdCardMapper.findIdCard
<mapper namespace="com.saima.mapper.IdCardMapper">
    <select id="findIdCard" resultType="idCard">
        select * from idcard where cid = #{cid}
    </select>
</mapper>

//Person中的查询
<resultMap id="fpid" type="person">
   <id property="pid" column="pid"></id>
   <result property="pname" column="pname"></result>
<!--       通过select的标签属性来连接idCard的查询语句,然后映射-->
   <association property="idCard" column="cid" javaType="idCard" select="com.saima.mapper.IdCardMapper.findIdCard">
   <id property="cid" column="cid"></id>
   <result property="cnum" column="cnum"></result>
   </association>
</resultMap>


<select id="findPersonAndIdCard" resultMap="fpid">
    select * from person
</select>
        一对多:collection 一对多    ofType=""

                方法一:和一对一的方式一样,但会产生冗余性代码........(有兴趣敲一下)

                方法二:将另一个关联的表当作一个集合属性 

public class Clazz {
    private  int clsid;
    private  String  clsname;
    //一个班级对应多个学生
    private List<Student> studentList;



<resultMap id="cs" type="com.hs.domain.Clazz">
        <id property="clsid" column="clsid"></id>
        <result property="clsname" column="clsname"></result>
        <collection property="studentList" ofType="com.hs.domain.Student">
            <id property="sid" column="sid"></id>
            <result property="sname" column="sname"></result>
        </collection>
</resultMap>

<select id="findAllStudentInClass" resultMap="cs" parameterType="int">
    select *  from  clazz c,student s where  c.clsid=s.clsid  and c.clsid=#{clsid}
</select>

                方法三:mybatis推荐的方式

public class Person {
    private int pid;
    private String pname;
//    private int pid; 一对多 对应多个BankCard卡
    private List<BankCard> bankCardList;


public class BankCard {
    private int bid;
    private String bnum;
    private double yueee;



<mapper namespace="com.saima.mapper.BankCardMapper">
    <select id="findBankCard" resultType="bankCard">
        select * from bankcard where pid = #{pid}
    </select>
</mapper>


<resultMap id="fpbc" type="person">
        <id property="pid" column="pid"></id>
        <result property="pname" column="pname"></result>
        <collection property="bankCardList" column="pid" ofType="bankCard" select="com.saima.mapper.BankCardMapper.findBankCard">
            <id property="bid" column="bid"></id>
            <result property="bnum" column="bnum"></result>
            <result property="yueee" column="yuee"></result>
        </collection>
    </resultMap>

    <select id="findPersonAndBankCard" resultMap="fpbc">
        select * from person
    </select>

                 2.动态sql

                   使用场景:多多条件查询,sql拼接,修改操作。

                   通过 if, choose, when, otherwise, trim, where, set, foreach等标签,可组合成非常灵活的SQL语句(自定义sql)

                   where标签添加where 关键字,并且可以去除开头的and 和 or 。
                   set标签用于添加set关键字,还可以去除前后多余的逗号。                                                               choose标签多条件查询,每次只执行一种结果。                                                                               trim标签可以代替where和set标签。                                                                                                   foreach标签可以循环遍历集合查询,通常用于批量查询。                                             

十,sql片段,日志,缓存

                1.sql片段

                定义sql片段:使用sql标签

                引用sql片段:include标签

<sql id="queryuser">
     select  *  from   user
</sql>


<select id="findUserByUsernameOrSex" parameterType="com.hs.domain.User" resultType="com.hs.domain.User">
        <include refid="queryuser"></include>
        <trim prefix="where"  prefixOverrides="and">
            <if test="username != null">
                username=#{username}
            </if>
            <if test="sex != null">
                and sex=#{sex}
            </if>
        </trim>

    </select>

                2.日志

                日志:就是记录程序的运行轨迹,方便查找关键信息,快速定位错误解决问题,日志可以打印在console控制台中,也可以写入日志文件*.log中。

                框架都支持日志:spring框架支持日志,springMVC支持日志,mybatis也支持日志

                日志组件:

                        日志对象:logger   

                        日志级别:OFF 关闭:最高级别,不输出日志。
                        FATAL 致命:输出非常严重的可能会导致应用程序终止的错误。
                        ERROR 错误:输出错误,但应用还能继续运行。
                        WARN 警告:输出可能潜在的危险状况。
                        INFO 信息:输出应用运行过程的详细信息。
                        DEBUG 调试:输出更细致的对调试应用有用的信息。
                        TRACE 跟踪:输出更细致的程序运行轨迹。
                        ALL 所有:输出所有级别信息。
                   常用的是:ERROR,WARN,INFO,DEBUG。

                   常见的日志api:

                   log4j,log4j2,logback==
                   slf4j提供了统一的日志接口:
                   使用:(1)导入jar包
                              (2)log4j.properties日志文件

#日志配置
log4j.rootLogger = DEBUG, stdout,fl

#输出到控制台
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %5p [%t] - %m%n


#输出到日志文件
log4j.appender.fl = org.apache.log4j.DailyRollingFileAppender
log4j.appender.fl.File=D:\\fl.log
log4j.appender.fl.layout = org.apache.log4j.PatternLayout
#日志信息可以自己配
log4j.appender.fl.layout.ConversionPattern = %5p [%t] - %m%n

十一,一些常用的配置

                mybatis别名:

<!--    起别名:方式1-->
<typeAliases>
          <typeAlias type="com.rui.pojo.User" alias="User"/>
      </typeAliases>
<!--    起别名:方式2-->
    <typeAliases>
        <package name="com.hs.domain"/>
    </typeAliases>

十二,延迟加载(懒加载)

                针对多表关联查询(mybatis官方推荐的写法)(鸡肋)
                不需要查询另一个表的数据时,就不去调用另一个表的查询

                配置:
                全局延迟加载:在mybatis.xml核心配置文件中加入,测试多表查询(不调用关联表的属性)

        <!--        开启全局延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--        true只要加载一个属性,其他属性也加载,false只加载需要的属性,其他属性不加载-->
        <setting name="aggressiveLazyLoading" value="false"/>
        <!--        执行哪些方法会导致立即加载,默认值equals,clone,hashCode,toString-->
        <setting name="lazyLoadTriggerMethods" value=""/>

                局部延迟加载:在接口映射文件的手动映射上association标签中加入属性fetType

                (1)注释全局加载设置
                (2)设置局部延迟加载
                        lazy:代表延迟加载
                        eager:代表饥饿加载(没有用延迟加载,调用接口表和关联表都会查询)

<association fetchType="lazy"  ...
<collection  fetchType="lazy"  ... 

十三:缓存(cache)

        介绍:针对查询操作
                对数据库的查询操作,保存到内存中,下次查询相同的sql语句,直接在缓存中获取。

        缓存失效:

                增删改操作会删除缓存,session flush或close都会删除缓存。

        一级缓存:

                一级缓存默认开启,作用域为session级别

        二级缓存:

                二级缓存默认关闭,需手动打开,作用域为sessionFactory级别
                实现:(1)在mybatis.xml核心配置文件中加入配置

<!--        开启二级缓存-->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>

                            (2)在需要的接口映射文件中加入

<mapper namespace="com.saima.mapper.StudentMapper">

<!--    二级缓存-->
    <cache/>

    <select id="findStu" resultType="student">
        select * from student
    </select>

</mapper>

        二级缓存技术:

                也可以采用第三方的二级缓存技术:ehcache,memcache,redis==

十四:数据库连接池(Druid)

                采用第三方的数据库连接池(不使用mybatis的数据库连接池)

                (1)导入jar包

                (2)配置druid数据源

  其他配置信息看官方:Druid连接池配置 (alibabacloud.com)https://www.alibabacloud.com/help/zh/analyticdb-for-mysql/latest/druid-connection-pool

<dataSource type="com.hs.util.DruidDataSourceFactory">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql:///hscrm?serverTimezone=Asia/Shanghai"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</dataSource>

     <!--配置初始化连接池大小、最小连接数、最大连接数。-->
     <property name="initialSize" value="5" />
     <property name="minIdle" value="10" /> 
     <property name="maxActive" value="20" />

     <!--配置获取连接等待超时的时间。-->
     <property name="maxWait" value="60000" />

     <!--配置一个连接在连接池中的最小生存时间、最大生存时间,超过最大生存时间会被移除,单位毫秒。-->
     <property name="minEvictableIdleTimeMillis" value="600000" />
     <property name="maxEvictableIdleTimeMillis" value="900000" />

                (3)自定义数据源工厂

public class DruidDataSourceFactory2 extends UnpooledDataSourceFactory {

    public   DruidDataSourceFactory2(){
        this.dataSource=new DruidDataSource();
    }

    @Override
    public DataSource getDataSource() {
        try {
            ((DruidDataSource)this.dataSource).init();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

        return  this.dataSource;
    }
}    

十五:逆向工厂(代码生成器)

        MybatisX的使用

                (1)idea中下载插件MybatisX    
                (2)新建一个项目,使用idea连接数据库,测试连接。    
                (3)选中表,右键点击MybatisX-Generator
                (4)配置生成代码在模块,父类包名,默认的和MP等

十六:注解

        常用的注解:直接在接口上以注解的方式写sql,需要在核心配置文件中映射接口的包。

                @Select
                @Update
                @Insert
                @Delete
                @Select

        动态Sql:

                @SelectProvider:

                        sql类:

public class StudentSql {

    public   String  findStudents(final Student student){

        //动态sql
        return  new SQL(){
            {
                SELECT("*");
                FROM("student");
                if(student.getSname()!=null){
                    OR().WHERE("sname=#{sname}");
                }
                if(student.getCid()!=0){
                    OR().WHERE("cid=#{cid}");
                }
                if(student.getClsid()!=0){
                    WHERE("clsid=#{clsid}");
                }
            }
        }.toString();

    }
}

  常见问题:if判断的是包装类还是基本数据类型 否则会出现nullpointException
                        如:int 就判断0    Integer 就判断 null    

                注解接口写的方式:

@SelectProvider(type = StudentSql.class,method = "findStudents")
List<Student>  findStudents(Student   student);

                其他注解就不做过多介绍!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值