Mybatis

1、认识mybatis

现在操作数据库使用的是:jdbc技术,比较麻烦,操作步骤多

mybatis是一个简化jdbc操作的一个框架。

什么是框架?框架是程序的一个半成品,无需程序员进行设计,只需要在框架的基础上完成自己的功能即可,简化了开发,提升开发效率

就像简历的模板

由于java是开源的,所以框架很多,在同一个技术上会出现多个框架

ORM框架是一类简化JDBC技术的框架的统称

O:Object 对象 java中的对象

R: Relationship 关系 数据库中的表

M: mapping 映射(关联)

ORM框架的原理:通过把java中的对象和数据库中的表进行关联后,从而进行JDBC简化操作的框架

ORM:mybatis hibernate jdbctemplate 等

mybatis框架的特点:

1、基于sql语句的框架

2、轻量级的半自动的框架(hibernate全自动,无需编写sql)

3、依赖数据库(不同数据库下,有不同的SQL语句)

4、对JDBC封装的持久化ORM框架


2、搭建mybatis的环境

1、新建maven项目

2、添加jar依赖

mysql mybatis

<dependencies>
    <!--MyBatis核心依赖-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.6</version>
    </dependency>

    <!--MySql驱动依赖-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
</dependencies>

3、编写配置文件 mybatis-cnfig.xml

需要有文件头,是mybatis官方提供的

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

mybatis-3-config.dtd是一个xml格式的文件,其作用就是限制引入该dtd文件的文件的格式

例如:必须包含哪些标签,标签的名字、顺序等

<?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>
    <!--JDBC环境配置:配置数据库连接信息-->
    <environments default="mysqlDB">
        <!--一个environment就是一个数据库的连接信息-->
        <environment id="mysqlDB">
            <!--事务管理器的类型
            JDBC,关键字:JDBC自身的事务管理器
            -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 数据源:连接池信息
                以后配置Druid连接池
            -->
            <dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
                <!--配置驱动-->
                <!--
                  property 指的是对应类的属性信息PooledDataSourceFactory
                  name里赋的值都是关键字
                -->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/db2105?useUnicode=true&amp;characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
        <environment id="oracleDB">
            <transactionManager type=""></transactionManager>
            <dataSource type=""></dataSource>
        </environment>

    </environments>
</configuration>


3、使用mybatis

1、新建实体类

【注意】实体类的属性名最好和表中的列名要一致(不区分大小写)

package com.qf.mybatispro2105.pojo;

import java.io.Serializable;

public class Dept implements Serializable {
    //确保无参构造方法和全参构造方法二选一

    public Dept() {
    }

    public Dept(int deptNo, String dName, String loc) {
        this.deptNo = deptNo;
        this.dName = dName;
        this.loc = loc;
    }

    private int deptNo;
    private String dName;
    private String loc;

    public int getDeptNo() {
        return deptNo;
    }

    public void setDeptNo(int deptNo) {
        this.deptNo = deptNo;
    }

    public String getdName() {
        return dName;
    }

    public void setdName(String dName) {
        this.dName = dName;
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }
}

2、编写dao---接口

package com.qf.mybatispro2105.dao;

import com.qf.mybatispro2105.pojo.Dept;

public interface DeptDao {
    //添加的方法
    int addDept(Dept dept);
}

3、编写接口所对应的映射文件

mybatis在使用过程中有两种方式:

方式1:基于接口的注解方式(用的少,不推荐)

方式2:基于接口的映射文件方式(推荐)

创建在resources目录下 DeptMapper.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qf.mybatispro2105.dao.DeptDao">
    <!--
      【说明】
      1、接口中的每一个方法,都要在映射文件中有与之对应的映射
      2、接口自身是支持方法重载,如果用在mybatis中的接口就不允许方法重载
         因为通过mybatis调用方法时,mybatis只通过方法名来调用,不看参数,所以方法重载会报错
    -->
    <!--
    方法的映射:
    id映射的是接口中方法的名字
    parameterType 映射参数的类型即可,
           注意:如果在mybatis的配置文件中没有过实体类信息,需要在此填写类的完整限定名,如果不写包名则找不到此类
    目前:只支持单个参数
    insert  update  delete  无需设置返回值类型,默认返回为int类型
    #{} 表达式,作用是到方法的形参中获取值,如果方法的形参是一个对象,那么获取的是对象的属性名
    -->
    <insert id="addDept" parameterType="com.qf.mybatispro2105.pojo.Dept">
        <!--编写sql-->
        insert into dept(deptno,dname,loc)
        values
        (#{deptNo},#{dName},#{loc})
    </insert>
</mapper>

4、把映射文件要注册到mybatis的配置文件中

mybatis-config.xml添加配置如下

<mappers>
    <mapper resource="DeptMapper.xml"></mapper>
</mappers>

mysql数据库自动提交事务---每条语句就是一个事务

mybatis关掉了mysql中自动提交事务的功能,需要手动提交事务

事务的本质:数据库缓存技术,执行到了缓存中

手动通过代码去控制事务称为编程式事务,有缺点:控制事务提交、回滚的代码分散在各个代码中

5、测试

package com.qf.mybatispro2105.test;

import com.qf.mybatispro2105.dao.DeptDao;
import com.qf.mybatispro2105.pojo.Dept;
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 TestDept {
    public static void main(String[] args) {
        //mybatis的工作流程
        SqlSession sqlSession=null;
        try {
            //1、通过流读取mybatis的配置文件信息
            InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");

            //、建SqlSessionFactoryBuilder,目的是为了创建SqlSessionFactory
            SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();

            //3、构建出SqlSessionFactory,目的是为了创建SqlSession对象
            SqlSessionFactory factory=builder.build(inputStream);

            //4、创建SqlSession对象
            sqlSession=factory.openSession();

            //mybatis是通过sqlSession操作数据库的
            //通过SqlSession对象得到接口的实现类对象(代理对象---mybatis内部使用了代理设计模式)
            DeptDao deptDao=sqlSession.getMapper(DeptDao.class);
            //调用方法
            Dept dept=new Dept(9010,"java2105部","设计城906室");
            int result=deptDao.addDept(dept);
            //手动提交事务
            sqlSession.commit();
            if(result==1){
                System.out.println("添加部门成功");
            }else{
                System.out.println("添加部门失败");
            }
        } catch (IOException e) {
            e.printStackTrace();
            //回滚事务
            sqlSession.rollback();
        }
    }
}

测试的方法:了解

package com.qf.mybatispro2105.test;

import com.qf.mybatispro2105.pojo.Dept;
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 TestDept2 {
    public static void main(String[] args) throws IOException {
        InputStream inputStream= Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
        SqlSessionFactory factory=builder.build(inputStream);
        SqlSession sqlSession=factory.openSession();
        Dept dept=new Dept(9011,"aaa","aaaaaa");
        //直接调用sqlSession对象的方法
        try{
            int result= sqlSession.insert("com.qf.mybatispro2105.dao.DeptDao.addDept",dept);
            sqlSession.commit();
            if(result==1){
                System.out.println("添加部门成功!");
            }else{
                System.out.println("添加部门失败!");
            }
        }catch (Exception ex){
            sqlSession.rollback();
        }
    }
}


4、细化mybatis的配置

 原因:在映射文件中直接使用了类名,没有添加包名,而且,在mybatis的配置文件中也没有进行实体类的配置

1、1:配置别名

<!--配置别名:指定实体类的名字,在mapper文件中就可以直接使用实体类的名字-->
<typeAliases>
    <!--缺点:需要逐个设置每个实体类-->
    <!--<typeAlias type="com.qf.mybatispro2105.pojo.Dept"></typeAlias>-->
    <!--告知mybatis扫描实体类的包,此包下的所有实体类都会被mybatis扫描到,进而识别到-->
    <package name="com.qf.mybatispro2105.pojo"/>
</typeAliases>

typeAliases的配置做了两件事

1、告知实体类的位置

2、给实体类命名别名,默认情况下别名就是类名的首字母小写

1、2:配置数据库信息

1、创建db.properties文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db2105pro?useUnicode=true&amp;characterEncoding=utf-8
username=root
password=root

2、在mybatis配置文件的开始,引入db.properties文件

<!--引入properties文件-->
<properties resource="db.properties"></properties>

3、修改数据库连接信息的配置,使用${}读取db.properties文件的内容

<?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文件-->
    <properties resource="db.properties"></properties>
    <!--配置别名:指定实体类的名字,在mapper文件中就可以直接使用实体类的名字-->
    <typeAliases>
        <!--缺点:需要逐个设置每个实体类-->
        <!--<typeAlias type="com.qf.mybatispro2105.pojo.Dept"></typeAlias>-->
        <!--告知mybatis扫描实体类的包,此包下的所有实体类都会被mybatis扫描到,进而识别到-->
        <package name="com.qf.mybatispro2105.pojo"/>
    </typeAliases>
    <!--JDBC环境配置:配置数据库连接信息-->
    <environments default="mysqlDB">
        <!--一个environment就是一个数据库的连接信息-->
        <environment id="mysqlDB">
            <!--事务管理器的类型
            JDBC,关键字:JDBC自身的事务管理器
            -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 数据源:连接池信息
                以后配置Druid连接池
            -->
            <dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
                <!--配置驱动-->
                <!--
                  property 指的是对应类的属性信息PooledDataSourceFactory
                  name里赋的值都是关键字
                -->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
        <environment id="oracleDB">
            <transactionManager type=""></transactionManager>
            <dataSource type=""></dataSource>
        </environment>

    </environments>
    <!--注册映射文件信息-->
    <mappers>
        <mapper resource="DeptMapper.xml"></mapper>
    </mappers>
</configuration>

1、3:配置日志文件

在开发过程中,想了解mybatis的执行过程,mybatis内部使用了log4j日志框架,来记录mybatis的工作过程,

可以通过设置log4j,把mybatis的运行过程打印到控制台上,便于调试程序

log4j具体内容,后面会具体学习,只会配置即可

1、创建log4j.properties 文件,【注意】必须是这个名字

2、复制进去配置信息

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

3、添加log4j的jar依赖

<!-- log4j日志依赖 https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
		<groupId>log4j</groupId>
		<artifactId>log4j</artifactId>
		<version>1.2.17</version>
</dependency>

4、在使用的时候,控制台打印mybatis的信息

1、4:配置mapper文件的存储位置

原因:

1、没有注册到mybatis的配置文件里

2、路径存储错误,默认到resources路径下查找映射的mapper文件

在pom.xml文件的最后,添加如下配置

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>*.xml</include>
                <include>**/*.xml</include><!--**/代表多级目录-->
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

在mybatis的配置文件中修改如下:

<mappers>
    <!--到resources下去寻找-->
    <mapper resource="com/qf/mybatispro2105/dao/DeptMapper.xml"></mapper>
</mappers>

把mapper文件的编码方式由UTF-8 改为utf8,mapper文件里的中文注释就会被支持


5、查询的实现

<!--查询功能
如果没有参数,则无需设置parameterType属性
select标签必须设置返回值类型
resultType 设置返回值类型:当查询的列名和实体类的属性名一致时,发生同名映射
mybatis如果有多个查询结果,默认返回List集合,只需通过resultType设置泛型即可

例如:查询出3条数据,mybatis就默认调用3次无参构造方法,创建3个Dept对象
     对每一条数据的各个列,按照同名的原则找对象的对应属性进行赋值,最后存在List集合中
-->
<select id="findDept" resultType="Dept">
    select deptno,dname,loc from dept
</select>


6、mybatis中的多参数处理

    <!--多条件查询
    当方法中有多个参数时,无需设置parameterType属性
    多参方式1:通过参数的顺序来获取
    -->
    <select id="findDept1" resultType="Dept">
        select deptno,dname,loc
        from dept
        where dname=#{arg0} and loc=#{arg1}
    </select>

    <!--
    多参方式2:通过@Patam()里定义的参数别名来获取
    -->
    <select id="findDept2" resultType="Dept">
        select deptno,dname,loc
        from dept
        where dname=#{dn} and loc=#{loc}
    </select>

    <!--
    多参方式3:参数是map集合,可以把多个参数放在map集合中,#{}获取map集合的的key所对应的value即可
    -->
    <select id="findDept3" resultType="Dept">
        select deptno,dname,loc
        from dept
        where dname=#{name} and loc=#{location}
    </select>
    <!--
    多参方式4:对象传参,#{}获取对象的属性名
    -->
    <select id="findDept4" resultType="Dept" parameterType="Dept">
        select deptno,dname,loc
        from dept
        where dname=#{dName} and loc=#{loc}
    </select>

【建议】通常优先使用对象传参,其次使用注解传参@Param

import com.mb.cloudCar.entity.Car;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface CarDao {
    //添加的方法
    int addCar(Car car);
    //修改的方法
    int updateCar(Car car);
    //删除的方法
    int deleteCar(String carId);
    //无条件查询
    List<Car> findCar();
    //多条件查询
    List<Car> findCar1(String carId,String money);
    List<Car> findCar2(@Param("ci")String carId,@Param("mo")String money);
    List<Car> findCar3(Map<String,Object> map);
    List<Car> findCar4(Car car);
    //模糊查询
    List<Car> findCar5(Car car);
}
<?xml version="1.0" encoding="UTF8" standalone="no"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mb.cloudCar.dao.CarDao">
    <insert id="addCar" parameterType="car">
        insert into car(carid,carnumber,money,cartype,dept,gas,safeman,yeartime,
                        displacement,model,datepurchase,datereg,status,deptcarperson,
                        finaltime,nextyeartime,power,totalmass,fare,onboarddata,
                        remarks,filledby,fillingtime)
                        values
                        (#{carId},#{carNumber},#{money},#{carType},#{dept},#{gas},#{safeMan},
                        #{yearTime},#{displacement},#{model},#{datepurchase},#{datereg},
                        #{status},#{deptCarperson},#{finalTime},#{nextYearTime},#{power},
                        #{totalMass},#{fare},#{onboarddata},#{remarks},#{filledby},#{fillingTime})
    </insert>

    <update id="updateCar" parameterType="com.mb.cloudCar.entity.Car">
        update car set carnumber=#{carNumber},money=#{money},cartype=#{carType},dept=#{dept},
                       gas=#{gas},safeman=#{safeMan},yeartime= #{yearTime},displacement=#{displacement},
                       model=#{model},datepurchase=#{datepurchase},datereg=#{datereg},
                       status=#{status},deptcarperson=#{deptCarperson},finaltime=#{finalTime},
                       nextyeartime=#{nextYearTime},power=#{power},totalmass= #{totalMass},
                       fare=#{fare},onboarddata=#{onboarddata},remarks=#{remarks},
                       filledby=#{filledby},fillingtime=#{fillingTime}
         where carid=#{carId}
    </update>

    <delete id="deleteCar" parameterType="String">
        delete from car where carid=#{carId}
    </delete>

    <select id="findCar" resultType="Car">
        select carid,carnumber,money,cartype,dept,gas,safeman,yeartime,
                        displacement,model,datepurchase,datereg,status,deptcarperson,
                        finaltime,nextyeartime,power,totalmass,fare,onboarddata,
                        remarks,filledby,fillingtime
        from car
    </select>

    <select id="findCar1" resultType="Car">
        select carid,carnumber,money,cartype,dept,gas,safeman,yeartime,
                        displacement,model,datepurchase,datereg,status,deptcarperson,
                        finaltime,nextyeartime,power,totalmass,fare,onboarddata,
                        remarks,filledby,fillingtime
        from car
        where carid=#{arg0} and money=#{arg1}
    </select>

    <select id="findCar2" resultType="Car">
         select carid,carnumber,money,cartype,dept,gas,safeman,yeartime,
                        displacement,model,datepurchase,datereg,status,deptcarperson,
                        finaltime,nextyeartime,power,totalmass,fare,onboarddata,
                        remarks,filledby,fillingtime
        from car
        where carid=#{ci} and money=#{mo}
    </select>

    <select id="findCar3" resultType="Car">
        select carid,carnumber,money,cartype,dept,gas,safeman,yeartime,
                      displacement,model,datepurchase,datereg,status,deptcarperson,
                        finaltime,nextyeartime,power,totalmass,fare,onboarddata,
                        remarks,filledby,fillingtime
        from car
        where carid=#{ci} and money=#{mo}
    </select>

    <select id="findCar4" resultType="Car" parameterType="Car">
         select carid,carnumber,money,cartype,dept,gas,safeman,yeartime,
                        displacement,model,datepurchase,datereg,status,deptcarperson,
                        finaltime,nextyeartime,power,totalmass,fare,onboarddata,
                        remarks,filledby,fillingtime
        from car
        where carid=#{carId} and money=#{money}
    </select>

    <select id="findCar5" resultType="Car" parameterType="Car">
        select carid,carnumber,money,cartype,dept,gas,safeman,yeartime,
                        displacement,model,datepurchase,datereg,status,deptcarperson,
                        finaltime,nextyeartime,power,totalmass,fare,onboarddata,
                        remarks,filledby,fillingtime
        from car
        where carid like CONCAT('%',#{carId},'%') and money like CONCAT('%',#{money},'%')
    </select>

</mapper>


7、模糊查询

<select id="findDept5" resultType="Dept" parameterType="string">
    select deptno,dname,loc
    from dept
    where loc like CONCAT('%',#{loc},'%')
</select>

分页查询

//分页查询
    List<Difficulty> findDifficultyByPage(@Param("start")int start,@Param("size")int size);
    //分页模糊查询总页数
    int findDifficultyCon(@Param("difficultyName") String difficultyName);
    //分页模糊查询
    List<Difficulty> findDifficultyByLike(@Param("difficultyName")String difficultyName,
                                          @Param("start")int start,
                                          @Param("size")int size);









//分页模糊查询总页数
    int findStageCon(@Param("stageName")String stageName ,@Param("subjectName")String subjectName);
    //分页模糊查询
    List<Stage> findStageByLike(@Param("stageName")String stageName,
                                @Param("subjectName")String subjectName,
                                @Param("start")int start,
                                @Param("size")int size);

    <!--分页查询-->
    <select id="findDifficultyByPage" resultType="Difficulty">
        select difficultyno,difficultyname,score
        from difficulty
        limit #{start},#{size}
    </select>

    <!--分页查询总页数-->
    <select id="findDifficultyCon" resultType="int">
        select count(difficultyno)
        from difficulty
        where difficultyname LIKE concat('%',#{difficultyName},'%')
    </select>

    <!--分页模糊查询-->
    <select id="findDifficultyByLike" resultType="Difficulty">
        select difficultyno,difficultyname,score
        from difficulty
        where difficultyname LIKE concat('%',#{difficultyName},'%')
        limit #{start},#{size}
    </select>







    <!--分页模糊查询总页数-->
    <select id="findStageCon" resultType="int">
        select count(stageid)
        from `subject` s
        INNER JOIN stage t ON s.subjectid=t.subjectid
        where t.stagename LIKE CONCAT('%',#{stageName},'%')
        and
            s.subjectname LIKE CONCAT('%',#{subjectName},'%')
    </select>

    <!--分页模糊查询-->
    <select id="findStageByLike" resultMap="stageMap">
        select t.stageid,t.stagename,s.subjectname
        from `subject` s
        INNER JOIN stage t ON s.subjectid=t.subjectid
        where t.stagename LIKE CONCAT('%',#{stageName},'%')
        and
        s.subjectname LIKE CONCAT('%',#{subjectName},'%')
        limit #{start},#{size}
    </select>

   //分页查询
    @GetMapping("/finddifficultybypage")
    public Map findDifficultyByPage(int page,int limit){
        List<Difficulty> list = difficultyService.findDifficultyByPage(page,limit);
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("code","0");
        map.put("msg","");
        map.put("count",difficultyService.findDifficulty().size());
        map.put("data",list);
        return map;
    }

    //分页模糊查询
    @GetMapping("/bylike")
    public Map findDifficultyByLike(String difficultyName,int page,int limit){
        int count = difficultyService.findDifficultyCon(difficultyName);
        List<Difficulty> list = difficultyService.findDifficultyByLike(difficultyName,page,limit);
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("code","0");
        map.put("msg","");
        map.put("count",count);
        map.put("data",list);

        return map;
    }




    //分页模糊查询
    @GetMapping("/findStageByLike")
    public Map findStageByLike(String stageName,String subjectName,int page,int limit){
    //获取总记录数
    int count = stageService.findStageCon(stageName,subjectName);
    //获取当前页数据
    List<Stage> list = stageService.findStageByLike(stageName,subjectName,page,limit);
    Map<String,Object> map = new HashMap<String,Object>();
    map.put("code","0");
    map.put("msg","");
    map.put("count",count);
    map.put("data",list);
    return map;
    }


8、主键回填

就是获取刚才添加的时候所需要的那个id值

订单表:order

id 订单id 自增

ordertime 订单时间

userID 下单人

totalprice 总价

1 2022-4-1 taoxiankun 200

订单详情表:orderdetail

id 自增主键

orderid 订单编号

goodsid 商品编号

1 1 kele

2 1 keyboard

主从表结构:

主表:订单基本信息

从表:订单的商品信息

对于主从表结构,在添加时应该在一个事务内,先插入主表,获得自增主键,然后在插入从表是要使用这个主键

如何在插入一个表后,获得我插入的主键?

使用主键回填的方式

主键:int类型,自增主键回填

<insert id="addOrder" parameterType="Order">
    <!--回填到Order对象的id属性里-->
    <!--回填方式之一
    keyProperty:回填到哪个属性中
    resultType:指定回填主键的类型
    order:在插入之前BEFORE,还是插入之后AFTER回填
    -->
    <selectKey keyProperty="id" resultType="int" order="AFTER">
        <!--获取自增的主键-->
        select LAST_INSERT_ID()
    </selectKey>
    insert into `order`(ordertime,totalprice,userid)
    values
    (#{orderTime},#{totalPrice},#{userId})
</insert>
<!--
useGeneratedKeys:告知Mybatis所执行的insert语句,会产生自动生成的主键值
keyProperty: 产生的哪一列值进行自增
keyColumn:该表在数据库中的主键
-->
<insert id="addOrder2" parameterType="Order" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
    <!--主键回填方式2-->
    insert into `order`(ordertime,totalprice,userid)
    values
    (#{orderTime},#{totalPrice},#{userId})
</insert>

【说明】

1、以上两种方式,只适用于int自增主键

2、本质是执行mysql的函数LAST_INSERT_ID()来获取的主键

主键:字符串类型,需要自己调用数据库的UUID函数,产生主键

顺序: 先产生主键,回填给实体类的属性

然后 执行insert ,获取刚才回填的主键

<?xml version="1.0" encoding="utf8" standalone="no"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qf.mybatispro2105.dao.Order2Dao">
    <insert id="addOrder2" parameterType="Order2">
        <selectKey keyProperty="id" resultType="String" order="BEFORE">
            <!--借助数据库的UUID()产生字符串类型主键
                回填给Order2对象的id属性
            -->

            select REPLACE(UUID(),'-','')
        </selectKey>

        insert into order2 (id,name)
        values (#{id},#{name})
    </insert>
</mapper>


9、封装一个工具类

原则:

1、复用

2、用好作用域

package com.qf.mybatispro2105.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 {
    //SqlSessionFactoryBuilder:作用域是局部变量级别,构建完SqlSessionFactory,就可以销毁
    //SqlSessionFactory:作用域时程序级别,是static,不断的创建sqlSession
    //sqlSession:是会话级别的,访问数据库之前创建,访问数据库之后销毁
    //声明session工厂
    private static SqlSessionFactory factory;
    //声明局部线程类,存放SqlSession
    private static final ThreadLocal<SqlSession> tl=new ThreadLocal<SqlSession>();
    static {

        //读取配置文件
        try {
            InputStream inputStream= Resources.getResourceAsStream("mybatis-config.xml");
            //局部
            SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
            factory=builder.build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //获得SqlSession的方法
    private static SqlSession openSession(){
        //到局部线程类中获取
        SqlSession session=tl.get();
        //判断是否获取到
        if(session==null){
            //则创建
            session=factory.openSession();
            //存入到局部线程类中
            tl.set(session);
        }
        return session;
    }
    //关闭session
    private static  void closeSession(){
        //到局部线程类里获取要关闭的sqlSession
        SqlSession session=tl.get();
        session.close();
        //从局部线程类删除
        tl.remove();   //删除当前线程ID的sqlsessiion
    }
    //提交事务
    public static void commit(){
        SqlSession sqlSession=MybatisUtil.openSession();
        sqlSession.commit();
        //关闭sqlSession
        MybatisUtil.closeSession();
    }
    //回滚事务
    public static void rollback(){
        SqlSession sqlSession=openSession();
        sqlSession.rollback();
        closeSession();
    }
    //获取接口实现类对象的方法
    public static <T extends Object> T getMapper(Class<T> clazz){
        SqlSession sqlSession=openSession();
        return sqlSession.getMapper(clazz);
    }
}

测试工具类

package com.qf.mybatispro2105.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 {
    //SqlSessionFactoryBuilder:作用域是局部变量级别,构建完SqlSessionFactory,就可以销毁
    //SqlSessionFactory:作用域时程序级别,是static,不断的创建sqlSession
    //sqlSession:是会话级别的,访问数据库之前创建,访问数据库之后销毁
    //声明session工厂
    private static SqlSessionFactory factory;
    //声明局部线程类,存放SqlSession
    private static final ThreadLocal<SqlSession> tl=new ThreadLocal<SqlSession>();
    static {

        //读取配置文件
        try {
            InputStream inputStream= Resources.getResourceAsStream("mybatis-config.xml");
            //局部
            SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
            factory=builder.build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //获得SqlSession的方法
    private static SqlSession openSession(){
        //到局部线程类中获取
        SqlSession session=tl.get();
        //判断是否获取到
        if(session==null){
            //则创建
            session=factory.openSession();
            //存入到局部线程类中
            tl.set(session);
        }
        return session;
    }
    //关闭session
    private static  void closeSession(){
        //到局部线程类里获取要关闭的sqlSession
        SqlSession session=tl.get();
        session.close();
        //从局部线程类删除
        tl.remove();   //删除当前线程ID的sqlsessiion
    }
    //提交事务
    public static void commit(){
        SqlSession sqlSession=MybatisUtil.openSession();
        sqlSession.commit();
        //关闭sqlSession
        MybatisUtil.closeSession();
    }
    //回滚事务
    public static void rollback(){
        SqlSession sqlSession=openSession();
        sqlSession.rollback();
        closeSession();
    }
    //获取接口实现类对象的方法
    public static <T extends Object> T getMapper(Class<T> clazz){
        SqlSession sqlSession=openSession();
        return sqlSession.getMapper(clazz);
    }
}


10、主键回填的应用

下订单时:写入订单表,订单详情表

要求:

1、在一个事务内

2、先插入订单主表,主键回填后,插入订单从表

在MVC分层下实现

dao:插入订单主表的方法---主键回填

插入订单从表的方法

service:控制事务,调用插入订单主表及插入订单从的dao方法

v: 构建商品集合

package com.qf.mybatispro2105.service.impl;

import com.qf.mybatispro2105.dao.OrderDao;
import com.qf.mybatispro2105.dao.OrderDetailDao;
import com.qf.mybatispro2105.pojo.Order;
import com.qf.mybatispro2105.pojo.OrderDetail;
import com.qf.mybatispro2105.service.OrderService;
import com.qf.mybatispro2105.util.DateUtil;
import com.qf.mybatispro2105.util.MybatisUtil;

import java.util.List;

public class OrderServiceImpl implements OrderService {
    //获取dao操作对象
    private OrderDao orderDao= MybatisUtil.getMapper(OrderDao.class);
    private OrderDetailDao orderDetailDao=MybatisUtil.getMapper(OrderDetailDao.class);
    public int setOrder(List<OrderDetail> details,String userId) {
        //先生成订单
        Order order=new Order();
        order.setUserId(userId);
        order.setTotalPrice(50);
        order.setOrderTime(DateUtil.getTime());
        int count=0;
        try{
            //插入订单
            int orderResult=orderDao.addOrder2(order);
            //经过一步执行,主键已经回填
            //遍历插入订单从表
            for(OrderDetail detail:details){
                //把订单表里的订单编号,赋值给订单详情独享
                detail.setOrderId(order.getId());
                //插入订单详情
                count+=orderDetailDao.addOrderDetail(detail);
            }
            //提交事务
            MybatisUtil.commit();


        }catch (Exception ex){
            //回滚事务
            MybatisUtil.rollback();
        }
        return count;
    }
}


11、ORM映射

针对查询操作而言

【面试题】当查询结果的列名和实体类的属性名不一致时,该如何处理?

方式1:sql命名别名,让别名和实体类的属性名一致

private int dno; //deptNo
private String name;  //dname
private String location;  //loc

命名别名

<select id="findDept6" resultType="Dept2">
    select deptno dno,dname `name`,loc location
    from dept
</select>

【说明】在单表查询中,使用别名可以解决不同名的问题,但是在主外键关系的表中将不适用

方式2:使用resultMap进行ORM映射

使用resultMap

完成一对一的映射:

在类中有个属性,属性是单个对象类型

<?xml version="1.0" encoding="utf8" standalone="no"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qf.mybatispro2105.dao.EmpDao">

    <!--编码进行映射
        id是自定义的resultMap的唯一标识
        type  要进行映射的实体磊
    -->
    <resultMap id="empMap" type="Emp">
        <!--映射主键列时使用id标签-->
        <id property="empNo" column="empno"></id>
        <!--其余列使用result标签进行映射-->
        <result property="eName" column="ename"></result>
        <result property="jobs" column="job"></result>
        <result property="com" column="com"></result>
        <result property="sal" column="sal"></result>
        <result property="joinDate" column="joindate"></result>
        <result property="mgrNo" column="mgrno"></result>
        <!--一对一映射:当属性为一个对象时,进行如下映射
        mybatis会创建javaType类型的对应,然后按照column和property的映射赋值
        把创建对象的地址赋值给属性  association property="dept"
        -->
        <!--映射dept对象-->
        <!--<association property="dept" javaType="Dept">

            <id property="deptNo" column="deptno"></id>
            <result property="dName" column="dname"></result>
            <result property="loc" column="loc"></result>
        </association>-->
        <association property="dept" javaType="Dept" resultMap="deptMap">

        </association>
    </resultMap>

    <!--声明dept的映射-->
    <resultMap id="deptMap" type="Dept">
        <id property="deptNo" column="deptno"></id>
        <result property="dName" column="dname"></result>
        <result property="loc" column="loc"></result>
    </resultMap>
    <!--
      当查询结果的列名或别名和实体类的属性名一致时,查询的返回值类型设置的是resultTpe
      如果不符合以上条件,返回值类型设置为resultMap
      二选一,不能同时存在
    -->
    <select id="findEmp" resultMap="empMap">
        select empno,ename,job,com,sal,joindate,mgrno,emp.deptno,
        dname,loc
        from emp
        inner join dept on emp.deptno=dept.deptno
    </select>

</mapper>

完成一对多映射:

一个类中的属性是集合类型,称为一对多映射

<?xml version="1.0" encoding="utf8" standalone="no"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qf.mybatispro2105.dao.EmpDao">

    <!--编码进行映射
        id是自定义的resultMap的唯一标识
        type  要进行映射的实体磊
    -->
    <resultMap id="empMap" type="Emp">
        <!--映射主键列时使用id标签-->
        <id property="empNo" column="empno"></id>
        <!--其余列使用result标签进行映射-->
        <result property="eName" column="ename"></result>
        <result property="jobs" column="job"></result>
        <result property="com" column="com"></result>
        <result property="sal" column="sal"></result>
        <result property="joinDate" column="joindate"></result>
        <result property="mgrNo" column="mgrno"></result>
        <!--一对一映射:当属性为一个对象时,进行如下映射
        mybatis会创建javaType类型的对应,然后按照column和property的映射赋值
        把创建对象的地址赋值给属性  association property="dept"
        -->
        <!--映射dept对象-->
        <!--<association property="dept" javaType="Dept">

            <id property="deptNo" column="deptno"></id>
            <result property="dName" column="dname"></result>
            <result property="loc" column="loc"></result>
        </association>-->
        <association property="dept" javaType="Dept" resultMap="deptMap">

        </association>
    </resultMap>

    <!--声明dept的映射-->
    <resultMap id="deptMap" type="Dept">
        <id property="deptNo" column="deptno"></id>
        <result property="dName" column="dname"></result>
        <result property="loc" column="loc"></result>
    </resultMap>
    <!--
      当查询结果的列名或别名和实体类的属性名一致时,查询的返回值类型设置的是resultTpe
      如果不符合以上条件,返回值类型设置为resultMap
      二选一,不能同时存在
    -->
    <select id="findEmp" resultMap="empMap">
        select empno,ename,job,com,sal,joindate,mgrno,emp.deptno,
        dname,loc
        from emp
        inner join dept on emp.deptno=dept.deptno
    </select>
    <!--一对多映射-->
    <resultMap id="empMap2" type="Emp">
        <!--映射主键列时使用id标签-->
        <id property="empNo" column="empno"></id>
        <!--其余列使用result标签进行映射-->
        <result property="eName" column="ename"></result>
        <result property="jobs" column="job"></result>
        <result property="com" column="com"></result>
        <result property="sal" column="sal"></result>
        <result property="joinDate" column="joindate"></result>
        <result property="mgrNo" column="mgrno"></result>
        <!--一对一映射-->
        <association property="dept" javaType="Dept" resultMap="deptMap"></association>
        <!--一对多映射-->
        <collection property="addressList" ofType="Address" resultMap="addMap">

        </collection>

    </resultMap>
    <!--定义地址映射-->
    <resultMap id="addMap" type="Address">
        <id property="id" column="id"></id>
        <result property="userId" column="empno"></result>
        <result property="phone" column="phone"></result>
        <result property="code" column="code"></result>
        <result property="content" column="content"></result>
    </resultMap>
    <select id="findEmp2" resultMap="empMap2">
        select empno,ename,job,com,sal,joindate,mgrno,emp.deptno,
        dname,loc,phone,code,content
        from emp
        inner join dept on emp.deptno=dept.deptno
        left join address on emp.empno=address.userid
    </select>

</mapper>

完成多对多映射

使用场景

学生表:student:stuno,stuname

课程表:course:courseno,coursename

学生和课程之间就是多对多的关系:一个学生可以选多门课程,一门课程也可以被多个学生选

中间表:选课表,通过中间表把学生和课程之间的多对多的关系进行体现

stu_counse: id stuno courseno

多对多查询3表联查

Students实体类

package com.qf.mybatispro2105.pojo;

import java.util.List;

public class Students {
    public Students() {
    }

    public Students(String stuNo, String stuName) {
        this.stuNo = stuNo;
        this.stuName = stuName;
    }

    public Students(String stuNo, String stuName, List<Course> courseList) {
        this.stuNo = stuNo;
        this.stuName = stuName;
        this.courseList = courseList;
    }

    private String stuNo;
    private String stuName;
    //所选课程的属性
    //一对多
    private List<Course> courseList;

    public List<Course> getCourseList() {
        return courseList;
    }

    public void setCourseList(List<Course> courseList) {
        this.courseList = courseList;
    }

    public String getStuNo() {
        return stuNo;
    }

    public void setStuNo(String stuNo) {
        this.stuNo = stuNo;
    }

    public String getStuName() {
        return stuName;
    }

    public void setStuName(String stuName) {
        this.stuName = stuName;
    }
}

Course实体类

package com.qf.mybatispro2105.pojo;

import java.util.List;

public class Course {
    public Course() {
    }

    public Course(String courseNo, String courseName) {
        this.courseNo = courseNo;
        this.courseName = courseName;
    }

    public Course(String courseNo, String courseName, List<Students> studentsList) {
        this.courseNo = courseNo;
        this.courseName = courseName;
        this.studentsList = studentsList;
    }

    private String courseNo;
    private String courseName;
    //选本门课的学生
    //一对多
    private List<Students> studentsList;

    public List<Students> getStudentsList() {
        return studentsList;
    }

    public void setStudentsList(List<Students> studentsList) {
        this.studentsList = studentsList;
    }

    public String getCourseNo() {
        return courseNo;
    }

    public void setCourseNo(String courseNo) {
        this.courseNo = courseNo;
    }

    public String getCourseName() {
        return courseName;
    }

    public void setCourseName(String courseName) {
        this.courseName = courseName;
    }
}

由于是双向的一对多关系,就是多对多的关系

查询:

1、查询学生,同时查询学生所选课程

<?xml version="1.0" encoding="utf8" standalone="no"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qf.mybatispro2105.dao.StudentDao">
    <resultMap id="stuMap" type="Students">
        <id property="stuNo" column="stuno"></id>
        <result property="stuName" column="stuname"/>
        <collection property="courseList" ofType="Course" resultMap="courseMap"></collection>
    </resultMap>
    <resultMap id="courseMap" type="Course">
        <id property="courseNo" column="courseno"/>
        <result property="courseName" column="coursename"/>
    </resultMap>
    <select id="findStudents" resultMap="stuMap">
        select s.stuno,stuname,c.courseno,c.coursename
        from students s
        left join stucourse sc on s.stuno=sc.stuno
        inner join course c on c.courseno=sc.courseno
    </select>
</mapper>

2、查询课程,同时查询选择该课程的学生

<?xml version="1.0" encoding="utf8" standalone="no"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qf.mybatispro2105.dao.CourseDao">
    <resultMap id="courseMap" type="Course">
        <id property="courseNo" column="courseno"/>
        <result property="courseName" column="coursename"/>
        <collection property="studentsList" ofType="Students" resultMap="stuMap"/>
    </resultMap>
    <resultMap id="stuMap" type="Students">
        <id column="stuno" property="stuNo"/>
        <result property="stuName" column="stuname"/>
    </resultMap>
    <select id="findCourse" resultMap="courseMap">
        select c.courseno,c.coursename,s.stuno,s.stuname
        from course c
        left join stucourse sc on c.courseno=sc.courseno
        inner join students s on s.stuno=sc.stuno
    </select>
</mapper>


12、动态sql

动态sql语句,SQL语句会根据条件进行动态的组装、拼接

java中的逻辑判断,也能使用sql语句的动态拼接,但是比较麻烦,mybatis提供了一些动态sql标签,简化编程。

动态sql的原理:ognl

动态SQL本质就是sql语句的拼接

每个动态标签都是sqlnode类,对标签进行判断、进行拼接

sql标签:把重复使用的sql或部分sql语句使用sql标签进行定义,需要的引入即可

<?xml version="1.0" encoding="utf8" standalone="no"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="common">
    <sql id="deptSql">
        select deptno,dname,loc
        from dept
    </sql>
</mapper>

<!--声明复用部分的sql-->
<sql id="deptSql">
    select deptno,dname,loc
</sql>
<select id="findDept7" resultType="Dept">
    <include refid="deptSql"></include>
    from dept
</select>
<select id="findDept8" resultType="Dept">
    <include refid="common.deptSql"></include>
</select>

在外部xml文件中声明复用的sql,引入时:命名空间.sql的ID namespace.id

if标签:判断

<select id="findDept9" parameterType="Dept" resultType="Dept">
    <include refid="common.deptSql"></include>
    where 1=1
    <if test="dName!=null">
        and dname=#{dName}
    </if>
    <if test="loc!=null">
        and loc=#{loc}
    </if>
</select>

where标签 :相当于where关键字

<select id="findDept10" parameterType="Dept" resultType="Dept">
    <include refid="common.deptSql">
    </include>
    <where>
        <if test="dName!=null">
            and dname=#{dName}
        </if>
        <if test="loc!=null">
            and loc=#{loc}
        </if>
    </where>
</select>

【作用】

1、判断是否添加where关键字

2、过滤第一个条件前面的 and 或or等关键字

Set标签:在Update语句中使用

<update id="updateDept2" parameterType="Dept">
    update dept
    <set>
        <if test="dName!=null">
            dname=#{dName},
        </if>
        <if test="loc!=null">
            loc=#{loc}
        </if>
    </set>
    where deptno=#{deptNo}
</update>

【作用】

1、相当于update语句中的set关键字

2、过滤掉 多余的,

trim标签:用来替代where、set标签

替代where

<select id="findDept10" parameterType="Dept" resultType="Dept">
    <include refid="common.deptSql">
    </include>
   <!-- <where>
        <if test="dName!=null">
            and dname=#{dName}
        </if>
        <if test="loc!=null">
            and loc=#{loc}
        </if>
    </where>-->
   <!--
   prefix:为开头的关键字
   prefixOverrides: 覆盖掉多余的and 或 or
   -->
   <trim prefix="where" prefixOverrides="and|or">
       <if test="dName!=null">
           and dname=#{dName}
       </if>
       <if test="loc!=null">
           and loc=#{loc}
       </if>
   </trim>
</select>

替换set标签

<update id="updateDept2" parameterType="Dept">
    update dept
    <!--
    <set>
        <if test="dName!=null">
            dname=#{dName},
        </if>
        <if test="loc!=null">
            loc=#{loc}
        </if>
    </set>
    -->
    <!--
    suffixOverrides:在每个条件的后面覆盖掉多余的,
    -->
    <trim prefix="set" suffixOverrides=",">
        <if test="dName!=null">
            dname=#{dName},
        </if>
        <if test="loc!=null">
            loc=#{loc},
        </if>
    </trim>
    where deptno=#{deptNo}
</update>

foreach标签:用于循环

参数描述取值
collection容器类型list、array、map
open起始符(
close结束符)
separator分隔符,
index下标号从0开始,依次递增
item当前项任意名称(循环中通过 #{任意名称} 表达式访问)

<delete id="deleteDept2">
    delete from dept
    where deptno in
    <!--
    collection:用来指定参数的类型  array-数组  list-list集合  map-map集合
    open:开头的字符
    close:结尾的字符
    separator:分隔符
    delete from dept where deptno in (9011,9012,9013)
    item:就是定义的变量,用来存放从数组/集合中取出的值
    -->
    <foreach collection="array" open="(" close=")" separator="," item="dno">
        #{dno}
    </foreach>
</delete>

【补充】为了提升效率,一条sql插入多个值

int addOrderDetail2(List<OrderDetail> list);
-- 一条语句如何插入多行值,这样提升效率
insert into orderdetail(orderid,goodsid,num)
VALUES
(5,'test1',1),
(5,'test2',1),
(5,'test3',1)
<insert id="addOrderDetail2" parameterType="list">
    insert into orderdetail(orderid,goodsid,num)
    values 
    <foreach collection="list" item="detail" separator=",">
        (#{detail.orderId},#{detail.goodsId},#{detail.num})
    </foreach>
</insert>


 13、mybatis的缓存技术(查询)

mybatis把从数据库中查询到的结果,给缓存到一个“地方”,下次再需要这个结果时,mybatis就不从数据库重新查询,而是到缓存里获取查询结果,目的是提高查询效率

mybatis根据缓存的地方不同,分为一级缓存、二级缓存

一级缓存:缓存在session中,是默认的缓存

当sqlsession没有关闭及更新的情况下缓存数据有效

sqlsession缓存失效的场景:

1、提交事务

2、close

3、flush

二级缓存:缓存在“文件中”,跨session, 本质是文件的序列化

【要求】实体类及相关内容必须实现Serializable接口

开启二级缓存配置:

在mybatis的配置文件中mybatis-config.xml

【注意】配置的顺序

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

在mapper映射文件中还需要配置

<cache/> <!--当前mapper中的所有查询都使用二级缓存,查询结果都换在文件中-->

如果某个方法不使用二级缓存,做如下配置

<!-- useCache="false" 当前查询结果不进行二级缓存-->
<select id="findDept6" useCache="false" resultType="Dept2">
    select deptno dno,dname `name`,loc location
    from dept
</select>

二级缓存失效:服务重启,一次程序运行 过程中都有效

服务关闭后,二级缓存的文件被删除

第一个服务请求的速度要慢:原因是要初始化很多东西。


14、配置Druid连接池

各种连接池性能对比

JDBC-Conn Pool

1 Thread

2 threads

5 threads

10 threads

20 threads

50 threads

Druid

898

1,191

1,324

1,362

1,325

1,459

tomcat-jdbc

1,269

1,378

2,029

2,103

1,879

2,025

DBCP

2,324

5,055

5,446

5,471

5,524

5,415

BoneCP

3,738

3,150

3,194

5,681

11,018

23,125

jboss-datasource

4,377

2,988

3,680

3,980

32,708

37,742

C3P0

10,841

13,637

10,682

11,055

14,497

20,351

Proxool

16,337

16,187

18,310(Ex)

25,945

33,706(Ex)

39,501 (Ex)

综合对比:Druid连接池的性能最高

mybatis下如何配置Druid连接池:

1、添加依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.16</version>
</dependency>

2、使用Druid连接池,替换mybatis自带的连接池

package com.qf.mybatispro2105.util;

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;

public class MyDruidDataSourceFactroy extends PooledDataSourceFactory {
    //在无参构造函数中,使用Druid连接池替换掉mybatis自带的连接池

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

3、修改配置文件

<dataSource type="com.qf.mybatispro2105.util.MyDruidDataSourceFactroy">
    <!--配置驱动-->
    <!--
      property 指的是对应类的属性信息PooledDataSourceFactory
      name里赋的值都是关键字
    -->
    <!--
    <property name="driver" value="${driver}"/>
    <property name="url" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>
    -->
    <!--Druid连接池有自己的属性-->
    <property name="driverClass" value="${driver}"/>
    <property name="jdbcUrl" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>
</dataSource>

 


15、mybatis分页插件的使用

 【面试题】mybatis的分页插件如何使用?工作原理?

可以使用原始的分页方式

1、添加依赖

<dependency>
		<groupId>com.github.pagehelper</groupId>
		<artifactId>pagehelper</artifactId>
		<version>5.1.10</version>
</dependency>

2、在mybatis-config的配置文件中,引入分页插件

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

3、使用

//分页查询
public List<Dept> findDept(int currentPage,int pageSize){

    //设置查询的分页
    //参数1:当前页
    //参数2:每页显示的记录数
    PageHelper.startPage(currentPage,pageSize);
    //得到所有部门数据
    List<Dept> list=deptDao.findDept();
    PageInfo<Dept> pageInfo=new PageInfo<Dept>(list);
    //getList() 返回的就是当前页的数据
    return pageInfo.getList();

}

【注意】在设置startPage之后的查询才会进行分页(对查询的sql拼接上Limit)

public Map<String,Object> findDept(int currentPage, int pageSize){
    Map<String,Object> map=new HashMap<String, Object>();
    //设置查询的分页
    //参数1:当前页
    //参数2:每页显示的记录数
    PageHelper.startPage(currentPage,pageSize);
    //得到所有部门数据
    List<Dept> list=deptDao.findDept();
    //PageInfo 可以获取 分页信息
    PageInfo<Dept> pageInfo=new PageInfo<Dept>(list);
    //getList() 返回的就是当前页的数据
    map.put("data",pageInfo.getList());
    //获取总页数
    map.put("totalPages",pageInfo.getPages());
    //获取记录数
    map.put("size",pageInfo.getSize());
    map.put("pre",pageInfo.getPrePage());
    map.put("next",pageInfo.getNextPage());
    return map;

}

简化的地方:

1、分页sql

2、无需自行计算总页数等信息


16、基于接口+注解的使用方式

mybatis两种使用方式:

1、接口+mapper映射文件 推荐 本质是代理模式实现

2、接口+注解 sql语句写在注解中 了解

public interface DeptDao2 {
    //添加部门
    @Insert("insert into dept(deptno,dname,loc)values(#{deptNo},#{dName},#{loc})")
    int addDept(Dept dept);

    //修改部门
    @Update("update dept set dname=#{dName},loc=#{loc} where deptno=#{deptNo}")
    int updateDept(Dept dept);

    //删除部门
    @Delete("delete from dept where deptno=#{deptNo}")
    int deleteDept(int deptNo);

    //查询
    @Select("select deptno,dname,loc from dept")
    List<Dept> findDept();
}

使用与单表的简单操作,如果多表连接查询、动态sql的使用上不能支持


17、懒加载、延迟加载

场景:查询员工信息,包括员工的部门信息(部门名字、部门位置等),但是在使用的时候,很少使用员工的部门信息,但是在查询员工信息时,却已经查询出

优化:查询时,只查询常用的员工信息,暂时不查询部门信息,当何时使用员工的部门信息时,现去查询部门信息

延迟加载:不能使用连接查询,连接查询一并都进行了查询

使用过程:

1、开启延迟加载

<!--设置-->
<settings>
    <setting name="cacheEnabled" value="true"/> <!--开启了二级缓存-->
    <setting name="lazyLoadingEnabled" value="true"/><!--开启懒加载-->
</settings>

2、查询主表

    <select id="findEmpByEmpNo" resultMap="lazyEmpMap" parameterType="int" >
        select empno,ename,job,com,sal,joindate,mgrno,deptno
        from emp
        where empno=#{empNo}
    </select>
    <resultMap id="lazyEmpMap" type="Emp">
        <!--映射主键列时使用id标签-->
        <id property="empNo" column="empno"></id>
        <!--其余列使用result标签进行映射-->
        <result property="eName" column="ename"></result>
        <result property="jobs" column="job"></result>
        <result property="com" column="com"></result>
        <result property="sal" column="sal"></result>
        <result property="joinDate" column="joindate"></result>
        <result property="mgrNo" column="mgrno"></result>
        <!--一对一 或一对多映射时完成懒加载操作-->
       <!--写的是实体类里的数据类型  要写完整的包名和准备懒加载的方法-->
        <association property="dept" javaType="Dept"
                     select="com.qf.mybatispro2105.dao.DeptDao.findDeptByNo" column="deptno">
            <id property="deptNo" column="deptno"/>
            <result property="loc" column="loc"/>
            <result property="dName" column="dname"/>
        </association>
    </resultMap>

3、懒加载查询方法

<select id="findDeptByNo" resultType="Dept" parameterType="int">
    select deptno,dname,loc from dept where deptno=#{deptNo}
</select>


18、mybatis的执行器---扩充

执行器:executor sqlsession通过执行器executor来执行sql语句

mybatis的executor分为以下下3种:

1、ExecutorType.SIMPLE:简单执行器,每次使用时创建,使用完毕销毁

2、ExecutorType.REUSE:可重复使用执行器,每次使用时创建,创建完毕后,存储在map集合中,使用后不销毁,下次继续使用

3、ExecutorType.BATCH:批处理执行器,一次可执行多条语句

如何指定执行器?


19、总结

【总结】

映射文件的编写:namespace---关联接口

insert update delete 对应着接口中的方法

id---方法名 parameterType ---参数类型(单参、自定义类需要完整限定名) 无需设置返回值类型

#{} 取值---直接去对应参数名称的值,取对象的属性值

先编译sql 然后赋值, 根据值的数据类型自动单引号---preparestatement对象

${} 取值 使用的statement对象

先赋值,不添加单引号 然后编译 不安全

【面试题】#{} 和${}的区别?

重点:mybatis的工作流程?

1、创建SqlSessionFactoryBuilder 对象,来创建SqlSessionFactory

2、读取mybatis的配置文件信息

3、创建SqlSessionFactory对象 builder.build(inputstream);

用来创建SqlSession

4、得到SqlSession对象

SqlSessionFactory.openSession();

【解释】java程序每次与数据进行连接,执行sql语句,返回结果的一完整过程,在mybatis就是一次会话

每次操作数据库都应该重新获取sqlSession,操作结束后,应该关闭sqlSession

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值