MyBatis学习总结

本文详细介绍了如何创建一个简单的MyBatis Maven项目,包括配置全局文件、映射文件、接口实现及测试。接着展示了MyBatis的增删改查操作,并深入解析了全局配置和SQL映射文件的属性设置,如插入操作获取自增ID、查询结果为List或Map。此外,还探讨了动态SQL的用法,如where、trim、foreach、choose标签等。最后,讲解了一级缓存和二级缓存的原理及其配置。
摘要由CSDN通过智能技术生成

目录

一、创建一个简单的mybatis项目(Maven版本)

1.创建maven项目,在pom.xml文件中导入mybatis的 依赖

2.在数据库中创建表

3.创建对应的JavaBean对象和接口方法

 4.创建mybatis的全局配置文件mybatis-config.xml

5.创建sql映射文件employeeDao.xml

6.编写测试方法

二、mybatis实现增删改查

1.编写数据库实体类

2.创建接口类

3.书写mybatis的全局配置文件和sql映射文件

4.编写测试方法

三、mybatis的全局配置

1.mybatis全局配置中的属性设置

2.sql映射文件的属性设置

2.1 insert操作的参数设置

2.2select查询的参数设置

    2.2.1返回值为list集合

    2.2.2 返回值为map集合

2.3自定义封装规则

2.4联合查询

2.4.1使用级联方式封装对象

2.4.2使用association联合查询定义对象的封装规则

2.5分步查询

四、动态SQL

1.使用where标签去掉sql中多余的and(只能去掉前面多余的)

2.使用trim去掉多余的and

3.使用foreach遍历添加元素

4.使用choose进行动态sql拼接

5.使用set进行非全字段更新

6.bind的作用

7.使用include抽取重用的sql语句

五、缓存

1.一级缓存

2.二级缓存

2.1在MyBatis-config.xml中添加cacheEnable属性

2.2在sql映射文件中加上cache标签

2.3对应的实体类要实现序列化接口

2.4二级缓存的相关属性

3.查询缓存的顺序

4.整合第三方缓存

4.1整合EhCahe的步骤


参考网址:https://mybatis.org/mybatis-3/zh/getting-started.html

一、创建一个简单的mybatis项目(Maven版本)

1.创建maven项目,在pom.xml文件中导入mybatis的 依赖

<dependencies>
	<!--mybattis包-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.1</version>
    </dependency>
    <!--数据库连接包-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.37</version>
    </dependency>
   
</dependencies>

2.在数据库中创建表

CREATE TABLE tbl_employee(

        id INT(11) PRIMARY KEY AUTO_INCREMENT,

        last_name VARCHAR(50),

        email VARCHAR(50),

        gender CHAR(1)

);

3.创建对应的JavaBean对象和接口方法

public class Employee {
    private Integer id ;
    private String lastName;
    private String email ;
    private String gender ;
}
public interface EmployeeDao {

    //按照员工id查询员工
    public Employee getEmpById(Integer id);
}

 4.创建mybatis的全局配置文件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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--配置数据库连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis_0325"/>
                <property name="username" value="root"/>
                <property name="password" value="123"/>
            </dataSource>
        </environment>
    </environments>
    <!--引用我们编写的每一个接口的实现文件-->
    <mappers>
        <mapper resource="employeeDao.xml"/>
    </mappers>
</configuration>

5.创建sql映射文件employeeDao.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名称空间,写接口的全类名,相当于告诉MyBatis这个配置文件是实现哪个接口的-->
<mapper namespace="com.hzj.dao.EmployeeDao">
    <!--id:写要实现的方法名-->
    <!--#{属性名}:表示取出传递过来的某个参数的值-->
    <select id="getEmpById" resultType="com.hzj.bean.Employee">
        select * from t_employee where id = #{id}
    </select>
</mapper>

6.编写测试方法

public class mybatisTest {
	@Test
    public void test() throws IOException {
        //1.根据配置文件创建一个SqlSessionFactory对象
        //SqlSessionFactory:是sqlSession工厂,负责创建SqlSessionFactory对象
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        Employee empById = null;

        //2.从sqlSessionFactory中获取和数据库的一次会话
        SqlSession openSession = sqlSessionFactory.openSession();
        try {
            //3.使用sqlSession操作数据库,获取到dao接口的实现
            EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
            empById = employeeDao.getEmpById(1);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            openSession.close();
        }
        System.out.println(empById);
    }
}

二、mybatis实现增删改查

1.编写数据库实体类

public class Employee {
    private Integer id;
    private String empName;
    private String email;
    private Integer gender;
}

2.创建接口类

public interface employeeDao {
    //根据id号查询员工
    public Employee getEmpById(Integer id);
    //员工修改
    public int updateEmployee(Employee employee);
    //根据id删除员工
    public boolean deletEmployee(Integer id);
    //添加员工
    public int insertEmployee(Employee employee);

}

3.书写mybatis的全局配置文件和sql映射文件

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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--配置连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis_0325"/>
                <property name="username" value="root"/>
                <property name="password" value="123"/>
            </dataSource>
        </environment>
    </environments>

    <!--引用我们编写的每一个接口的实现文件-->
    <mappers>
        <mapper resource="employeeDao.xml"/>
    </mappers>
</configuration>

 employeeDao.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名称空间,写接口的全类名,相当于告诉MyBatis这个配置文件是实现哪个接口的-->
<mapper namespace="com.hzj.dao.employeeDao">

    <!--select表示表示查询
        id:写要实现的方法名
        #{属性名}:表示取出传递过来的某个参数的值
        返回值类型为数据库实体类-->
    <!--public Employee getEmpById(Integer id);-->
    <select id="getEmpById" resultType="com.hzj.bean.Employee">
        select * from t_employee where id = #{id}
    </select>

    <!--
        增删改不用写返回值类型;增删改是返回影响多少行
        mybatis会自动判断,
            如果是数字(int,long),返回数字
            如果是boolean(影响0行自动封装false)
    -->
    <!--public int updateEmployee(Employee employee);-->
    <update id="updateEmployee">
        update t_employee set empname=#{empName} , gender=#{gender} , email=#{email} where id=#{id}
    </update>

    <!--public boolean deletEmployee(Integer id);-->
    <delete id="deletEmployee">
        delete from t_employee where id=#{id}
    </delete>

    <!--public int insertEmployee(Employee employee);-->
    <insert id="insertEmployee">
        insert into t_employee(empname,gender,email) values(#{empName},#{gender},#{email})
    </insert>

</mapper>

4.编写测试方法

public class MybatisCRUDTest {
    //生成一个工厂类
    SqlSessionFactory sqlSessionFactory;
    //在方法执行之前运行
    @Before
    public void initSqlSessionFactory() throws IOException {
        //1.根据配置文件创建一个SqlSessionFactory对象
        //SqlSessionFactory:是sqlSession工厂,负责创建SqlSessionFactory对象
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void test() throws IOException {
        //得到sqlsession对象,true代表自动提交
        SqlSession openSession = sqlSessionFactory.openSession();
        //获取到接口的实现
        employeeDao employeeDao = openSession.getMapper(employeeDao.class);
        try {
            Employee empById = employeeDao.getEmpById(1);
            System.out.println(empById);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            openSession.close();
        }

    }
    /*
    * 增删改要提交事务两种方法
    *   1.在得到sqlsession对象时设置自动提交
*       SqlSession sqlSession = 
			sqlSessionFactory.openSession(true);
    *   2.在调用方法之后,调用commit()手动提交
    * */
    @Test
    public void InsertTest(){
         //得到sqlsession对象,true代表自动提交事务
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        try {
            employeeDao mapper = sqlSession.getMapper(employeeDao.class);
            int i = mapper.insertEmployee(new Employee(null, "hzjx", "hzjx@zhj.com", 1));
            System.out.println(i);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //增删改要提交事务
            //sqlSession.commit();
            sqlSession.close();
        }
    }

    @Test
    public void updateTest(){
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        try {
            employeeDao employeeDao = sqlSession.getMapper(employeeDao.class);
            int i = employeeDao.updateEmployee(new Employee(3, "huang", "hzj@zh", 1));
            System.out.println(i);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //sqlSession.commit();
            sqlSession.close();
        }
    }

三、mybatis的全局配置

mybatis中有两个重要的配置文件

1、全局配置文件:mybatis-config,xml;知道mybatis正确运行的全局设置

2、SQL映射文件:EmpoyeeDao.xml;对Dao接口方法的实现描述

细节:

1、SqlSession openSession = sqlSessionFactory.openSession();//获取到接口的实现

      employeeDao employeeDao = openSession.getMapper(employeeDao.class);

        //获取到的是接口的代理对象

2、SqlSessionFactory 和SqlSession

       SqlSessionFactory创建SqlSession对象,Factory只new一次就好

       SqlSession:相当于connection和数据库进行交互,和数据库的一次会话,每次都应该创建一个新的SqlSession;

1.mybatis全局配置中的属性设置

properties:可以引入外部文件

setting:可以改变mybatis的默认行为

typeAliases:可以为常用的javaBean起别名,在使用时就不用写全类名,写别名就可以获取对象

详细信息进 --> https://mybatis.org/mybatis-3/zh/getting-started.html

<?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="jdbcConfig.properties"></properties>

    <!--settings会改变MyBatis运行时行为-->
    <settings>
        <!--name配置项的key;value:配置项的值
        mapUnderscoreToCamelCase   是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。
        以下是满足驼峰命名时的行为
           java:loginAccount   数据库:login_account
           满足就可自动注入
        -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <!--类型别名;为常用的类型(javaBean)起别名-->
    <typeAliases>
        <!--别名默认是类名(不区分大小写),配置文件中就可以不用写全类名直接写类名就好了-->
       <!-- <typeAlias type="com.hzj.bean.Employee" alias="emp"></typeAlias>-->
        <!--批量起别名,默认别名都是类名-->
        <!--<package name="com.hzj.bean"/>-->
        <!--最后还是推荐使用全类名-->
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--配置连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--引用我们编写的每一个接口的实现文件-->
    <!--
    url:从磁盘或者网络路径引用
    resource:在类路径下找sql的映射文件
    class:直接引用接口的全类名
        需要将xml放在接口的同一路径下,文件名跟接口名相同
    -->
    <mappers>
        <mapper resource="employeeDao.xml"/>
    </mappers>
</configuration>

2.sql映射文件的属性设置

2.1 insert操作的参数设置

获取插入刚刚插入数据库的数据id

1、数据库支持id自增

        设置userGeneratedKeys="true"和keyProperty="属性名";

2、数据不支持id自增

        先从数据中查询最大的id+1,再赋值给employee的id属性
 

<!--让MyBatis自动的将自增的id赋值给传入的employee对象的id属性
    userGeneratedKeys="true":原生jdbc获取自增主键的方法
    keyProperty="";将刚才自增的id封装给哪个属性
-->
<insert id="insertEmployee" useGeneratedKeys="true" keyProperty="id">
    insert into t_employee(empname,gender,email) values(#{empName},#{gender},#{email})
</insert>
<!--数据库不支持id自增时获取id
        先从数据库中查询最大的id+1,把它赋值给employee的id属性
-->
<insert id="insertEmployee2" >
    /*查询主键,order表示运行顺序
    order="BEFORE"
        在核心sql语句运行之前查询id,将查到的id赋值给JavaBean中的某个属性,
      注意写入返回值类型resultType="integer"*/
    <selectKey order="BEFORE" resultType="integer" keyProperty="id">
        select max(id)+1 from t_employee
    </selectKey>
    insert into t_employee(id,empname,gender,email) values(#{id},#{empName},#{gender},#{email})
</insert>

测试方法

@Test
public void test02() throws IOException {
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    try {
        employeeDao mapper = sqlSession.getMapper(employeeDao.class);
        Employee employee = new Employee(null, "hzjx", "hzjx@zhj.com", 1);
        int i = mapper.insertEmployee(employee);
        System.out.println(i);
        System.out.println("刚才插入的id:"+employee.getId());
        System.out.println(employee);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        //增删改要提交事务
        //sqlSession.commit();
        sqlSession.close();

    }

}

/*数据库不支持自增id时,获取id属性*/
@Test
public void test03() throws IOException {
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    try {
        employeeDao mapper = sqlSession.getMapper(employeeDao.class);
        Employee employee = new Employee(null, "hzjx", "hzjx@zhj.com", 1);
        int i = mapper.insertEmployee2(employee);
        System.out.println(i);
        System.out.println("刚才插入的id:"+employee.getId());
        System.out.println(employee);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        //增删改要提交事务
        //sqlSession.commit();
        sqlSession.close();

    }

}

2.2select查询的参数设置

传入参数的方法
    1、单个参数
        基本类型:
            取值:
#{xx}
    2
、多个参数
        取值:不能使用
#{参数名}(无效)
        可用的取值方式:
01(参数的索引)或者param1param2(第几个参数paramN)
       
原因:只要传入多个参数:Mybatis会自动将这些参数封装在一个map中,封装时使用的key就是参数的索引或者参数的第几个标识
        <select id="getEmpById2" resultType="com.hzj.bean.Employee">
            select * from t_employee where id = #{0} and empname=#{1}
        </select>

       
我们可以使用在参数上使用Param:为参数指定key,这样map封装参数时,就会使用我们指定的key
        public Employee getEmpById2(@Param("id") Integer id, @Param("empname") String name);
        <select id="getEmpById2" resultType="com.hzj.bean.Employee">
            select * from t_employee where id = #{id} and empname=#{empname}
        </select>

    3
、传入map
       
取值:#{key}

    4
、传入了pojo对象
        取值:
#{pojo的属性名} 

<!—
    select表示查询
    id:写要实现的方法名
    #{属性名}:表示取出传递过来的某个参数的值-->
<!--public Employee getEmpById(Integer id);-->
<select id="getEmpById" resultType="com.hzj.bean.Employee">
    select * from t_employee where id = #{id}
</select>

<!--传入多个参数-->
<!--public Employee getEmpById2(Integer id,String name);-->
<select id="getEmpById2" resultType="com.hzj.bean.Employee">
    select * from t_employee where id = #{id} and empname=#{empname}
</select>

<!--传入map-->
<!--public Employee getEmpByMap(Map<String,Object> map);-->
<select id="getEmpByMap" resultType="com.hzj.bean.Employee">
    select * from t_employee where id = #{id} and empname=#{empname}
</select>
@Test
public void testSelect() throws IOException {
    //得到sqlsession对象,true代表自动提交
    SqlSession openSession = sqlSessionFactory.openSession();
    //获取到接口的实现
    employeeDao employeeDao = openSession.getMapper(employeeDao.class);
    try {
        
        //多个参数
        Employee empById = employeeDao.getEmpById2(1,"admin");
        System.out.println(empById);
        
        //map参数
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("id", 1);
        map.put("empname", "admin");
        Employee empByMap = employeeDao.getEmpByMap(map);
        System.out.println("empByMap-->"+empByMap);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        openSession.close();
    }

}

2.2.1返回值为list集合

1、设置<select>的返回值类型为集合中的元素类型

      mybatis会自动把数据封装成list返回

<!--
//查询所有员工
public List<Employee> getAllEmps();
如果返回值是集合,写的是集合里面元素的类型
-->
<select id="getAllEmps" resultType="com.hzj.bean.Employee">
    select * from t_employee
</select>

测试方法

SqlSessionFactory sqlSessionFactory;
@Before
public void initSqlSessionFactory() throws IOException {
    //1.根据配置文件创建一个SqlSessionFactory对象
    //SqlSessionFactory:是sqlSession工厂,负责创建SqlSessionFactory对象
    String resource = "mybatis.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}

@Test
public void testSelectAll() throws IOException {
    //得到sqlsession对象,true代表自动提交
    SqlSession openSession = sqlSessionFactory.openSession();
    //获取到接口的实现
    employeeDao employeeDao = openSession.getMapper(employeeDao.class);
    try {
        List<Employee> allEmps = employeeDao.getAllEmps();
        for (Employee employee:allEmps) {
            System.out.println(employee);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        openSession.close();
    }

运行结果

Employee{id=1, empName='admin', email='hzj@hzj', gender=1}

Employee{id=5, empName='hzjx', email='hzjx@zhj.com', gender=1}

Employee{id=6, empName='hzjx', email='hzjx@zhj.com', gender=1}

Employee{id=7, empName='hzjx', email='hzjx@zhj.com', gender=1}

Employee{id=8, empName='hzjx', email='hzjx@zhj.com', gender=1}

Employee{id=9, empName='hzjx', email='hzjx@zhj.com', gender=1}

Employee{id=10, empName='hzjx', email='hzjx@zhj.com', gender=1}

2.2.2 返回值为map集合

1、返回值为一个map直接设置resultType="map"

2、返回值为多个map

        字段中的主键做为map中的key,value是这个记录封装的对象

        在接口方法中加上@MapKey("id")注解,将id做为map的key

        返回值类型写对应的元素类型

<!--    //返回一个mao
public Map<String,Object> getEmpByIdReturnMap(Integer id);
-->
<select id="getEmpByIdReturnMap" resultType="map">
    select * from t_employee where id = #{id}
</select>

<!--
        //返回所有员工封装在map中
    //字段中的主键做为key,value是这条记录封装号的对象
    //将id做为key
    @MapKey("id")
    public Map<Integer,Employee> getAllEmpsReturnMap();

    返回多个map集合时,返回值类型写元素类型
-->
<select id="getAllEmpsReturnMap" resultType="com.hzj.bean.Employee">
    select * from t_employee
</select>
@Test
public void testSelectReturnMap() throws IOException {
    SqlSession openSession = sqlSessionFactory.openSession();
    //获取到接口的实现
    employeeDao employeeDao = openSession.getMapper(employeeDao.class);
    try {
        //查询单条记录,封装map
        Map<String, Object> map = employeeDao.getEmpByIdReturnMap(1);
        System.out.println(map);

        //查询返回多个map
        Map<Integer, Employee> allEmpsReturnMap = employeeDao.getAllEmpsReturnMap();
        System.out.println(allEmpsReturnMap);

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        openSession.close();
    }

}

运行结果

{empname=admin, gender=1, id=1, login_account=a, email=hzj@hzj}

{1=Employee{id=1, empName='admin', email='hzj@hzj', gender=1},

5=Employee{id=5, empName='hzjx', email='hzjx@zhj.com', gender=1},

6=Employee{id=6, empName='hzjx', email='hzjx@zhj.com', gender=1},

7=Employee{id=7, empName='hzjx', email='hzjx@zhj.com', gender=1},

8=Employee{id=8, empName='hzjx', email='hzjx@zhj.com', gender=1},

9=Employee{id=9, empName='hzjx', email='hzjx@zhj.com', gender=1},

10=Employee{id=10, empName='hzjx', email='hzjx@zhj.com', gender=1}}

2.3自定义封装规则

当数据库列名于实体属性名不一一对应时

1、数据库满足驼峰命名规则,开启驼峰命名法

<settings>
       
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

2、在写sql语句时,给对应的列名起别名

3、使用自定义规则

<mapper namespace="com.hzj.dao.CatDao">
    <!--public Cat getCatById(Integer id);
        resultMap="myCat"指定查出数据封装结果时,使用自定义规则
    -->
    <select id="getCatById" resultMap="myCat">
        select * from t_employee where id = #{cid}
    </select>
    <!--自定义封装规则-->
    <resultMap id="myCat" type="com.hzj.bean.Cat">
        <!--指定主键列的对应规则
            column="id",指定哪一列是主键列
            property="",指定cat哪个属性封装id这一列数据
        -->
        <id column="id" property="id"></id>
        <!--普通列-->
        <result property="cempName" column="empname"></result>
        <result property="cemail" column="email"></result>
        <result property="cgender" column="gender"></result>
    </resultMap>
</mapper>
@Test
public  void testCat(){
    SqlSession openSession = sqlSessionFactory.openSession();
    CatDao catDao = openSession.getMapper(CatDao.class);
    Cat catById = catDao.getCatById(1);
    System.out.println(catById);
    openSession.close();
}

2.4联合查询

2.4.1使用级联方式封装对象

public class Department {

        private Integer id ;

        private String departmentName ;

        // 省略 get/set方法

}

public class Employee {

        private Integer id ;

        private String lastName;

        private String email ;

        private String gender ;

        private Department dept ;

        // 省略 get/set 方法

}

使用级联方式赋值

<select id="getEmployeeAndDept" resultMap="myEmpAndDept" >
    SELECT e.id eid, e.last_name, e.email,e.gender ,d.id did, d.dept_name FROM
    tbl_employee e , tbl_dept d WHERE e.d_id = d.id AND e.id = #{id}
</select>
<resultMap type="com.atguigu.mybatis.beans.Employee" id="myEmpAndDept">
    <id column="eid" property="id"/>
    <result column="last_name" property="lastName"/>
    <result column="email" property="email"/>
    <result column="gender" property="gender"/>

    <!-- 级联的方式 -->
    <result column="did" property="dept.id"/>
    <result column="dept_name" property="dept.departmentName"/>
</resultMap>

2.4.2使用association联合查询定义对象的封装规则

<select id="getEmployeeAndDept" resultMap="myEmpAndDept" >
    SELECT e.id eid, e.last_name, e.email,e.gender ,d.id did, d.dept_name FROM
    tbl_employee e , tbl_dept d WHERE e.d_id = d.id AND e.id = #{id}
</select>

<resultMap type="com.atguigu.mybatis.beans.Employee" id="myEmpAndDept">
    <id column="eid" property="id"/>
    <result column="last_name" property="lastName"/>
    <result column="email" property="email"/>
    <result column="gender" property="gender"/>
    <!--联合查询-->
    <association property="dept" javaType="com.atguigu.mybatis.beans.Department">
        <id column="did" property="id"/>
        <result column="dept_name" property="departmentName"/>
    </association>
</resultMap>

2.5分步查询

 实际的开发中,对于每个实体类都应该有具体的增删改查方法,也就是 DAO 层, 因此

对于查询员工信息并且将对应的部门信息也查询出来的需求,就可以通过分步的方式

完成查询。

1 、先通过员工的 id 查询员工信息

2、 再通过查询出来的员工信息中的外键(部门 id)查询对应的部门信息.

<select id="getEmployeeAndDeptStep" resultMap="myEmpAndDeptStep">
    select id, last_name, email,gender,d_id from tbl_employee where id =#{id}
</select>
<resultMap type="com.atguigu.mybatis.beans.Employee" id="myEmpAndDeptStep">
    <id column="id" property="id" />
    <result column="last_name" property="lastName"/>
    <result column="email" property="email"/>
    <result column="gender" property="gender"/>
    <!--使用association调用另一个查询方法实现联合查询
        fetchType="lazy"表示延迟加载-->
    <association property="dept"                                     
    select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById" 
    column="d_id" fetchType="lazy"></association>
</resultMap>
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>

四、动态SQL

public class Teacher {​​​​​​​
    private Integer id;
    private
String name;
    private
String course;
    private
String address;
    private
Date birth;

}

1.使用where标签去掉sql中多余的and(只能去掉前面多余的)

<select id="getTeacherByCondition" resultMap="teacherMap">
    select * from t_teacher

    <!--where标签可以去掉前面多余的and-->
    <where>
        <!--if:传入非常强大的判断条件,OGNL表达式
        test=""编写判断条件
        id!=null;取出传入的JavaBean属性中的id值,判断是否为空
        空串‘’
        and,or-->
        <if test="id!=null">
            id > #{id}
        </if>

        <if test="name!=null and  name!=''">
            and teacherName like #{name }
        </if>
        <if test="birth!=null">
           and birth_date &lt; #{birth}
        </if>
    </where>
</select>

2.使用trim去掉多余的and

<select id="getTeacherByCondition" resultMap="teacherMap">
    select * from t_teacher

    <!--trim()截取字符串
      prefix="where" ;为下面的sql语句添加一个前缀
      prefixOverrides="" ;取出整体字符串前面多余的字符
      suffix="" ;为整体添加后缀
      suffixOverrides="";后面哪个多了可以去掉
      -->
    <trim prefix="where" 
          prefixOverrides="and"  
          suffixOverrides="and">
    <!--if:传入非常强大的判断条件,OGNL表达式
        test=""编写判断条件
        id!=null;取出传入的JavaBean属性中的id值,判断是否为空
        空串‘’
        and,or-->
        <if test="id!=null">
            id > #{id}
        </if>

        <if test="name!=null and  name!=''">
            and teacherName like #{name }
        </if>
        <!--遇到特殊符号要使用转义字符-->
        <if test="birth!=null">
           and birth_date &lt; #{birth}
        </if>
    </trim>
</select>
@Test
public void test() throws IOException {
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        TearcherDao tearcherDao = openSession.getMapper(TearcherDao.class);
       
        Teacher teacher2 = new Teacher();
        teacher2.setId(1);
        teacher2.setName("%m%");
        teacher2.setBirth(new Date());
        List<Teacher> teacherList = tearcherDao.getTeacherByCondition(teacher2);
        System.out.println(teacherList);
    }finally {
        openSession.close();
    }

}

3.使用foreach遍历添加元素

<!--输出list集合存在的id号对应的数据
    public List<Teacher> getTeacherByIdIn(@Param("ids") List<Integer> ids);-->
<select id="getTeacherByIdIn" resultMap="teacherMap">
    select * from t_teacher where id in
    <!--foreach遍历集合
      collection:指定要遍历的集合
      item:为每次遍历出的元素起一个变量名
      open:指定以什么开头
      close:指定以什么结尾
      separator:为每一个遍历的元素添加分隔符
      -->
    <foreach collection="ids" 
             item="id_item" 
             open="("   
             close=")" 
             separator=",">
        #{id_item}
    </foreach>
</select>
@Test
public void test() throws IOException {
    SqlSession openSession = sqlSessionFactory.openSession();

    try {
        TearcherDao tearcherDao = openSession.getMapper(TearcherDao.class);
        List<Teacher> list = tearcherDao.getTeacherByIdIn(Arrays.asList(1, 2, 3, 4));
        System.out.println(list);
    }finally {
        openSession.close();
    }

}

4.使用choose进行动态sql拼接

<!--public List<Teacher> getTeacherByIdChoose(Teacher teacher);-->
<select id="getTeacherByIdChoose" resultMap="teacherMap">
    select * from t_teacher
<where>
<!--若id中有值,就按id号查询
    若id中没值,name中有值再按name查询
    若name没值,birth有值就按birth查询
    若都没值,则查询所有数据-->
    <choose>
        <when test="id!=null">
            id=#{id}
        </when>
        <when test="name!=null and name!=''">
            teacherName=#{name}
        </when>
        <when test="birth!=null">
            birth_date=#{birth}
        </when>
        <otherwise>
            1=1
        </otherwise>
    </choose>
</where>
</select>
@Test
public void test() throws IOException {
    SqlSession openSession = sqlSessionFactory.openSession();

    try {
        TearcherDao tearcherDao = openSession.getMapper(TearcherDao.class);
        Teacher teacher2 = new Teacher();
        teacher2.setId(1);
        teacher2.setName("lucy");
        List<Teacher> teacherByIdChoose = tearcherDao.getTeacherByIdChoose(teacher2);
        System.out.println(teacherByIdChoose);

    }finally {
        openSession.close();
    }

}

运行结果

[teacher{id=3, name='lucy', course='英语', address='罗湖区', birth=Thu Jul 12 00:00:00 CST 2018}]

5.使用set进行非全字段更新

<!--根据传入对象的值,更新数据库中的数据
    public int updateTeacher(Teacher teacher);-->
<update id="updateTeacher" >
    update t_teacher
    <!--只更新有传入值的数据-->
    <set>
        <if test="name!=null and !name.equals(&quot;&quot;)">
            teacherName=#{name}
        </if>
        <if test="course!=null and !course.equals(&quot;&quot;)">
            class_name=#{course}
        </if>
        <if test="address!=null and !address.equals(&quot;&quot;)">
            address=#{address}
        </if>
        <if test="birth!=null and !birth.equals(&quot;&quot;)">
            birth_date=#{birth}
        </if>

        <where>
            id=#{id}
        </where>
    </set>
</update>
@Test
public void test02() throws IOException {
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        TearcherDao tearcherDao = openSession.getMapper(TearcherDao.class);

        Teacher teacher2 = new Teacher();
        teacher2.setId(1);
        teacher2.setName("hzjAdmin");

        int i = tearcherDao.updateTeacher(teacher2);
        System.out.println(i);
    }finally {
        openSession.commit();
        openSession.close();
    }
}

6.bind的作用

/*绑定一个表达式的值给一个变量*/
<bind name="_name" value="'%'+name+'%'"></bind>
<if test="name!=null and  name!=''">
    and teacherName like #{_name }
</if>

7.使用include抽取重用的sql语句

<!-- 抽取可重用的sql语句-->
<sql id="selectSql">select * from t_teacher</sql>

 <!--    public Teacher getTeacherById(Integer id);-->
 <select id="getTeacherById"  resultMap="teacherMap">
    <!--引用抽取的sql-->
     <include refid="selectSql"></include>
      where id=#{id}
 </select>

五、缓存

1.一级缓存

一级缓存是sqlSession级别的缓存

    1、不同的sqlSession使用不同的一级缓存,只有在同一个sqlSession期间查询到的数据才会保存到这个sqlSession的缓存中,下次使用这个sqlSession才能拿到缓存的数据

    2、同一个方法,不同的参数,没查询过没保存

    3、在sqlSession期间执行增删改操作,会清空一级缓存

    4、手动清空缓存

        openSession.clearCache();

    5、每次查询先看一级缓存中有没有,没有再去查询数据库

2.二级缓存

一级缓存sqlSession提交或者关闭后,一级缓存中的数据才会存到二级缓存中,二级缓存是namespace级别的缓存

二级缓存需要手动开启

2.1在MyBatis-config.xml中添加cacheEnable属性

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

2.2在sql映射文件中加上cache标签

<mapper namespace="com.hzj.dao.TeacherDao.xml">
    <!--使用二级缓存-->
    <cache></cache>
</mapper>

2.3对应的实体类要实现序列化接口

     public class Teacher implements Serializable

2.4二级缓存的相关属性

1 eviction=“FIFO”:缓存回收策略:

    LRU – 最近最少使用的:移除最长时间不被使用的对象。

    FIFO – 先进先出:按对象进入缓存的顺序来移除它们。

    SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。

    WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

    默认的是 LRU。

2 flushInterval:刷新间隔,单位毫秒

    默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新

3 size:引用数目,正整数

    代表缓存最多可以存储多少个对象,太大容易导致内存溢出

4 readOnly:只读,true/false

    true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。

    false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。

3.查询缓存的顺序

1.不会出现一级缓存和二级缓存中有同一个数据的情况

    1、一级缓存中的数据连接关闭后才传给二级缓存

    2、若二级缓存没有想要的数据,才会看一级缓存,一级缓存没有再去查数据库,数据库的查询结果放在一级缓存中

2.任何时候都是先看二级缓存、再看一级缓存,都没有才去查数据库

顺序 :二 --> 一 –-> 数据库

4.整合第三方缓存

1) 为了提高扩展性。MyBatis 定义了缓存接口 Cache。我们可以通过实现 Cache 接口来定义二级缓存

2) EhCache 是一个纯 Java 的进程内缓存框架,具有快速、精干等特点,是 Hibernate 中默认的 CacheProvider

4.1整合EhCahe的步骤

4.1.1导入ehcache的包以及整合类和日志包

ehcache-core-2.6.8.jar

mybatis-ehcache-1.0.3.jar

slf4j-api-1.6.1.jar

slf4j-log4j12-1.6.2.jar

4.1.2编写ehcache.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <!-- 磁盘保存路径 -->
    <diskStore path="D:\atguigu\ehcache" />

    <defaultCache
    maxElementsInMemory="1000" maxElementsOnDisk="10000000" eternal="false
    overflowToDisk="true"
    timeToIdleSeconds="120"
    timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120"   
    memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>
<!-- 属性说明:
l diskStore:指定数据在磁盘中的存储位置。
l defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache
便会采用<defalutCache/>指定的的管理策略
以下属性是必须的:
l maxElementsInMemory - 在内存中缓存的element的最大数目
l maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
l eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始
终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
l overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁
盘上
以下属性是可选的:
l timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过
timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置
时间无穷大
l timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活
时间无穷大
diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认
是30MB.每个Cache都应该有自己的一个缓冲区. l diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是
false。
l diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120
秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
l memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时
候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU
(最不常使用)和FIFO(先进先出)
-->

3 配置 cache 标签

<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值