• Mybatis的使用


    1.MyBatis的简介

    概述:和数据库进行交互,持久化层框架(SQL映射框架)

    操作数据库的其他工具和框架:

    1)从原始的JDBC--》dbUtils(QueryRunner)--》jdbcTemplate,以上这些都称为工具,工具是对一些功能的简单封装,而框架则是某个领域的整体解决方案:考虑缓存,考虑异常处理问题,考虑部分字段映射问题等等

    2)Hibernate:数据库交互的框架(ORM框架,全自动框架 )

    Mybatis

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

    • MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。

    • MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录.

    为什么要使用MyBatis?

    1.MyBatis是一个半自动化的持久化层框架。

    2.JDBC

    • SQL夹在Java代码块里,耦合度高导致硬编码内伤

    • 维护不易且实际开发需求中sql是有变化,频繁修改的情况多见

    3.Hibernate和JPA

    • 长、难、复杂SQL,对于Hibernate而言处理也不容易

    • 内部自动生产的SQL,不容易做特殊优化。

    • 基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难。导致数据库性能下降。

    4.对开发人员而言,核心sql还是需要自己优化,
    MyBatis框架中sql和java编码分开,功能边界清晰,一个专注业务、一个专注数据。

    2.创建第一个MyBatis程序

    创建第一个MyBatis的步骤:

    1)导包:

    • mybatis-3.4.1.jar
    • mysql-connector-java-8.0.17.jar
    • log4j-1.2.17.jar(建议导入,这样在mybatis关键的环节就会有日志打印,依赖类路径下一个log4f.xml配置文件)

    2)写配置(全局配置文件和dao接口的实现文件)

    • 第一个配置文件:成为mybatis的全局配置文件,知道mybatis如何正确运行,比如连接向哪个数据库
    • 第二个配置文件:编写的每一个方法都是如何向数据库发送sql语句,如何执行的,相当于接口的实现类
    • 我们写的dao接口的实现文件,MyBatis是不知道的,需要在全局配置文件中注册

    3)测试

    • 根据全局配置文件先创建一个sqlSessionFactory
    • 从sqlSessionFactory中获取sqlSession对象操作数据库即可

    代码实现:

    环境部署:

    数据库操作:

    新建数据库(my):create database my;

    新建User表:

    create table user_01(
    	id int not null auto_increment PRIMARY KEY,
    	username VARCHAR(20),
    	`PASSWORD` VARCHAR(20),
    	role VARCHAR(20)
    )
    

    bean组件(User.java):

    package com.luyi.bean;
    
    public class User {
    	private Integer id;
    	private String username;
    	private String password;
    	private String role;
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public String getUsername() {
    		return username;
    	}
    	public void setUsername(String username) {
    		this.username = username;
    	}
    	public String getPassword() {
    		return password;
    	}
    	public void setPassword(String password) {
    		this.password = password;
    	}
    	public String getRole() {
    		return role;
    	}
    	public void setRole(String role) {
    		this.role = role;
    	}
    	public String toString() {
    		return "User [id=" + id + ", username=" + username + ", password="
    				+ password + ", role=" + role + "]";
    	}
    	
    }
    

    dao层接口(UserDao.java)

    package com.luyi.dao;
    
    import com.luyi.bean.User;
    
    public interface UserDao {
    	public User getUser(int i);
    }
    

    写配置:

    第一个配置文件(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.cj.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/my?serverTimezone=UTC"/>
            <property name="username" value="root"/>
            <property name="password" value="123"/>
          </dataSource>
        </environment>
      </environments>
      <!-- 引入我们自己编写的每一个接口实现文件 -->
      <mappers>
      <!-- resource:表示从类路径下找资源 -->
        <mapper resource="UserDao.xml"/>
      </mappers>
    </configuration>
    

    第二个配置文件(UserDao.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.luyi.dao.UserDao">
    <!-- select标签用来定义一个查询操作 -->
    <!-- 
    	id:用来定义方法名,相当于这个配置是对某个方法的实现
    	resultType:指定方法运行后的返回值类型(查询操作必须指定)
     -->
      <select id="getUser" resultType="com.luyi.bean.User">
        select * from user where id = #{id}
      </select>
    </mapper>
    

    测试(MyBatisTest01.java文件):

    package com.luyi.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    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 com.luyi.bean.User;
    import com.luyi.dao.UserDao;
    
    public class MyBatisTest01 {
    
    	public static void main(String[] args) throws IOException {
    		//根据全局配置文件创建一个SqlSessionFactory
    		//sqlSessionFactory:是SqlSession工厂,负责创建SqlSession对象
    		//sqlSession:sql会话(代表和数据库的一次会话)
    		String resource = "mybatis-config.xml";
    		InputStream inputStream = Resources.getResourceAsStream(resource);
    		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    		
    		User user = null;
    		SqlSession openSession = null;
    		try {
    			//获取和数据库的一次会话:相当于getConnection()
    			openSession = sqlSessionFactory.openSession();
    			
    			//使用sqlSession操作数据库,获取到dao接口的实现
    			UserDao userDao = (UserDao) openSession.getMapper(UserDao.class);
    			user = userDao.getUser(3);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			openSession.close();
    		}
    		System.out.println(user);
    		
    	}
    }
    

    补充:Mybatis导入dtd文件使得写xml文件时有提示

    MyBatis的CRUD

    在上面程序进行简单的修改:

    User.java:

    package com.luyi.bean;
    
    public class User {
    	private Integer id;
    	private String username;
    	private String password;
    	private String role;
    	
    	public User(){};
    	public User(Integer id, String username, String password, String role) {
    		super();
    		this.id = id;
    		this.username = username;
    		this.password = password;
    		this.role = role;
    	}
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public String getUsername() {
    		return username;
    	}
    	public void setUsername(String username) {
    		this.username = username;
    	}
    	public String getPassword() {
    		return password;
    	}
    	public void setPassword(String password) {
    		this.password = password;
    	}
    	public String getRole() {
    		return role;
    	}
    	public void setRole(String role) {
    		this.role = role;
    	}
    	public String toString() {
    		return "User [id=" + id + ", username=" + username + ", password="
    				+ password + ", role=" + role + "]";
    	}
    	
    }
    

    UserDao.java

    package com.luyi.dao;
    
    import com.luyi.bean.User;
    
    public interface UserDao {
    	public User getUser(int i);
    	public int updateUser(User user);
    	public int deleteUser(int i);
    	public int addUser(User user);
    }
    

    测试文件:

    package com.luyi.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    import junit.framework.TestCase;
    
    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 com.luyi.bean.User;
    import com.luyi.dao.UserDao;
    
    public class Test01 extends TestCase {
    	public SqlSessionFactory initSqlSessionFactory() throws IOException{
    		String resource = "mybatis-config.xml";
    		InputStream inputStream = Resources.getResourceAsStream(resource);
    		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    		return sqlSessionFactory;
    	}
    	
    	public void testSelect() throws IOException{
    		SqlSession openSession = initSqlSessionFactory().openSession();
    		UserDao userDao = openSession.getMapper(UserDao.class);
    		
    		try {
    			User user = userDao.getUser(3);
    			System.out.println(user);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			openSession.close();
    		}
    	}
    	
    	public void testUpdate() throws IOException{
    		SqlSession openSession = initSqlSessionFactory().openSession();
    		UserDao userDao = openSession.getMapper(UserDao.class);
    		User user = new User(3, "luyi", "123", "student");
    		
    		try {
    			int row = userDao.updateUser(user);
    			System.out.println(row);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			openSession.commit();
    			openSession.close();
    		}
    	}
    	
    	public void testDelete() throws IOException{
    		SqlSession openSession = initSqlSessionFactory().openSession();
    		UserDao userDao = openSession.getMapper(UserDao.class);
    		
    		try {
    			int row = userDao.deleteUser(3);
    			System.out.println(row);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			openSession.commit();
    			openSession.close();
    		}
    	}
    	
    	public void testInsert() throws IOException{
    		SqlSession openSession = initSqlSessionFactory().openSession();
    		UserDao userDao = openSession.getMapper(UserDao.class);
    		User user = new User(null, "天才", "77777", "student");
    		
    		try {
    			int row = userDao.addUser(user);
    			System.out.println(row);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			openSession.commit();
    			openSession.close();
    		}
    	}
    }
    

    3.全局配置文件的配置

    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配置文件 -->
    <properties resource="dbconfig.properties"></properties>
      <environments default="development">
        <environment id="development">
          <transactionManager type="JDBC"/>
          <dataSource type="POOLED">
            <property name="driver" value="${driverclass}"/>
            <property name="url" value="${jdbcurl}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
          </dataSource>
        </environment>
      </environments>
      <mappers>
        <mapper resource="UserDao.xml"/>
      </mappers>
    </configuration>
    

    settings-修改mybatis的运行时行为

    比较常用的是设置是否开启驼峰命名映射:

    <!-- 改变 MyBatis 的运行时行为 -->
    <settings>
    	<!-- 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 -->
    	<setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    

    typeAliases-给java类型起别名

    代码示例(推荐还是使用全类名):

    <typeAliases>
    	<!-- 默认起的别名是这个类名 -->
    	<typeAlias type="com.luyi.bean.User" alias="User"/>
    	<!-- 批量起别名,name指定包名 ,默认别名为这个类名
    	批量起别名,如果也想自定义别名,就在那个要起别名的bean上面加个@Alias("别名")注解-->
    	<package name="com.luyi.bean"/>
    </typeAliases>
    

    typeHandlers-类型处理器

    概述:默认的类型处理器已经够我们的基本使用了,基本上不用再去注册自顶的类型处理器了

    <typeHandlers>
    	<typeHandler handler="自定义的类型处理器"/>
    </typeHandlers>
    

    plugins插件

    概述:插件是MyBatis提供的一个非常强大的机制,我们可以通过插件来修改MyBatis的一些核心行为,插件通过动态代理机制,可以介入四大对象的任何一个方法的执行

    • Executor:执行器,负责执行sql语句
    • ParameterHandler:参数处理器,预编译搞好后,给预编译设置参数
    • ResultSetHandler:结果处理器
    • StatementHandler:用来预编译参数

    environments-配置环境

    代码示例:

    <environments default="development">
        <environment id="development">
        <!-- JDBC – 这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务范围。 -->
          <transactionManager type="JDBC"/>
          <!-- 有三种内建的数据源类型(也就是 type=”[UNPOOLED|POOLED|JNDI]”) -->
          <dataSource type="POOLED">
            <property name="driver" value="${driverclass}"/>
            <property name="url" value="${jdbcurl}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
          </dataSource>
        </environment>
    </environments>
    

    databaseIdProvider-用于数据库移植

    代码示例:

    全局配置文件:

    <databaseIdProvider type="DB_VENDOR">
    	<property name="MySQL" value="mysql"/>
    	<property name="SQL Server" value="sqlServer"/>
    	<property name="Oracle" value="oracle"/>
    </databaseIdProvider>
    

    SQL映射文件:

    <select id="getUser" resultType="User" databaseId="mysql">
    	select * from user where id = #{id}
    </select>
    
    <select id="getUser" resultType="User" databaseId="oracle">
    	select * from user where id = #{id}
    </select>
    
    <select id="getUser" resultType="User" >
    	select * from user where id = #{id}
    </select>
    

    mappers-映射器

    注册单个(代码示例):

    <mappers>
      	<!-- 
      		url:可以从磁盘或者网络路径引用
      		resource:在类路径下找sql映射文件
      		class:直接引用接口的全类名;可以将xml放在和dao接口同目录下,而且文件名和接口名一致
      		class的另一种用法:把select,update,delete,insert标签里的sql语句通过注解直接写在dao文件对应的方法上,那么我们的class也只能是写这个有注解的类的全类名了
      	 -->
        
        <mapper class="com.luyi.dao.UserDao"/>
    </mappers>
    

    批量注册:

    注意:批量注册这里的所有dao接口文件以及SQL映射配置文件都得放在com.luyi.dao包下才会注册成功,为了比较规范好看,我们可以在conf文件夹下重新新建一个也叫做com.luyi.dao的package

    4.SQL映射文件

    这个文件中的所有标签:

    • cache:和缓存有关
    • cache-ref:和缓存有关
    • parameterMap:参数map,废弃的,原本是用来做复制参数映射
    • insert,delete,upate,select
    • sql:抽取1可重用的sql

    insert,delete,upate,select里的属性

    获取自增主键的值代码示例:

    <!-- 
    	useGeneratedKeys="true":原生jdbc获取自增主键的方法
    	keyProperty="":将刚才自增的id封装给哪个属性
    -->
    <insert id="addUser" useGeneratedKeys="true" keyProperty="id">
    	insert into user(username, password, role) values(#{username}, #{password}, #{role})
    </insert>
    
    <!--再在测试文件中直接获取这个id的值是可以获取得到的-->
    

    获取非自增主键的值的代码示例:

    <insert id="addUser">
    	<!-- order="BEFORE":在核心sql语句之前先运行一个查询sql查到id,将查到的id赋值给javaBean的id属性 -->
    	<selectKey order="BEFORE" resultType="Integer" keyProperty="id">
    	select max(id) + 1 from user  		
    	</selectKey>
    	insert into user(username, password, role) values(#{username}, #{password}, #{role})
    </insert>
    

    SQL映射文件中参数传递

    • 单个参数:

      • 基本类型:取值的方法为:#{随便写都能取到这个参数}
    • 多个参数

      • 取值时通过#{参数名}是取不出来的
      • 只能通过0,1(参数的索引)或者param1,param2(第几个参数)获取参数值
      • 原因是只要传入了多个参数,mybatis会自动的将这些参数封装在一个map中,封装时使用的key就是参数的索引和参数的第几个表示
    • 为参数指定key,命名参数,通过@Param注解实现,这是我们推荐的写法,我们可以告诉mybatis,封装参数map的时候别乱来,使用我们指定的key

    • 传入map:直接使用#{key}取出

    • 传入pojo:取出参数的方法为:#{pojo的属性名}

    参数处理

    参数也可以指定一个特殊的数据类型:

    • javaType 通常可以从参数对象中来去确定
    • 如果 null 被当作值来传递,对于所有可能为空的列,jdbcType 需要被设置,原因是null值对于oracle数据库是不认识的,会导致报错(常用设置)
    • 对于数值类型,还可以设置小数点后保留的位数:
    • mode 属性允许指定 IN,OUT 或 INOUT 参数。如果参数为 OUT 或 INOUT,参数对象属性的真实值将会被改变,就像在获取输出参数时所期望的那样。
    • 参数位置支持的属性:
      javaType、jdbcType、mode、numericScale、
      resultMap、typeHandler、jdbcTypeName、expression

    #{key}与${key}的区别

    • #{key}:获取参数的值,预编译到SQL中。安全。
    • ${key}:获取参数的值,拼接到SQL中。有SQL注入问题。ORDER BY ${name};${key}还可以用于不是参数的位置,如${user}(表名),而#{key}则不行

    查询结果返回list

    代码示例:

    SQL映射文件:

    ...
    <select id="getAll" resultType="com.luyi.bean.User">
      	select * from user
    </select>
    ...
    

    UserDao.java:

    public List<User> getAll();
    

    Test.java:

    public void testSelect() throws IOException{
    		SqlSession openSession = initSqlSessionFactory().openSession();
    		UserDao userDao = openSession.getMapper(UserDao.class);
    		
    		try {
    			List<User> list = userDao.getAll();
    			
    			for(User user:list){
    				System.out.println(user);
    			}
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			openSession.close();
    		}
    	}
    

    查询结果返回map

    查询单条封装成map代码示例:

    UserDao.xml:

    <select id="getAllReturnMap" resultType="map">
      	select * from user where id = #{id}
    </select>
    

    UserDao.java:

    public Map<String, Object> getAllReturnMap(int i);
    

    Test.java:

    public void testSelectReturnMap() throws IOException{
    		SqlSession openSession = initSqlSessionFactory().openSession();
    		UserDao userDao = openSession.getMapper(UserDao.class);
    		
    		try {
    			Map<String, Object> map = userDao.getAllReturnMap(6);
    			System.out.println(map);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			openSession.close();
    		}
    	}
    

    查询多条返回Map代码示例:

    UserDao.java:

    //注解标志id为map的key
    @MapKey("id")
    public Map<Integer, User> getAllReturnMaps();
    

    UserDao.xml:

    <select id="getAllReturnMaps" resultType="com.luyi.bean.User">
    	select * from user 
    </select>
    

    Test.java:

    public void testSelectReturnMaps() throws IOException{
    		SqlSession openSession = initSqlSessionFactory().openSession();
    		UserDao userDao = openSession.getMapper(UserDao.class);
    		
    		try {
    			Map<Integer, User> map = userDao.getAllReturnMaps();
    			
    			System.out.println(map);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			openSession.close();
    		}
    	}
    

    自定义映射规则,自己定义每一列数据和javaBean的映射规则

    默认的映射规则(mybatis自动封装结果集的规则):

    • 按照列名和属性名一一对应的规则(不区分大小写)
    • 如果不一一对应
      • 开启驼峰命名法:满足驼峰命名规则的一一对应
      • 起别名

    自定义映射规则:

    SQL映射文件:

    ...
    <select id="getAll" resultMap="myUser">
    	select * from user
    </select>
    <!--type:指定为哪个javaBean自定义封装规则,id=“”:唯一标识,让别名在后面给引用-->
    <resultMap type="com.luyi.bean.User" id="myUser">
    	<id property="id" column="id"/>
    	<result property="username" column="name"/>
    	<result property="password" column="pw"/>
    	<result property="role" column="role"/>
    </resultMap>
    

    联合查询(1对1)

    环境搭建(数据库表的数据):

    key表:

    lock表:

    代码实现(使用了if标签:OGNL表达式):

    所有的bean文件:

    //Key.java
    package com.luyi.bean;
    
    public class Key {
    	private Integer id;
    	private String keyName;
    	private Lock lock;
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public String getKeyName() {
    		return keyName;
    	}
    	public void setKeyName(String keyName) {
    		this.keyName = keyName;
    	}
    	public Lock getLock() {
    		return lock;
    	}
    	public void setLock(Lock lock) {
    		this.lock = lock;
    	}
    	public String toString() {
    		return "Key [id=" + id + ", keyName=" + keyName + ", lock=" + lock
    				+ "]";
    	}
    	
    }
    
    //Lock.java
    package com.luyi.bean;
    
    public class Lock {
    	private Integer id;
    	private String lockName;
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public String getLockName() {
    		return lockName;
    	}
    	public void setLockName(String lockName) {
    		this.lockName = lockName;
    	}
    	public String toString() {
    		return "Lock [id=" + id + ", lockName=" + lockName + "]";
    	}
    	
    }
    

    dao文件:

    //KeyDao.java
    package com.luyi.dao;
    
    import com.luyi.bean.Key;
    
    public interface KeyDao {
    	public Key getKeyById(int id);
    }
    

    SQL映射配置文件:

    <!--KeyDao.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">
    <mapper namespace="com.luyi.dao.KeyDao">
      <select id="getKeyById" resultMap="mykey">
        select k.id kid, k.keyName, k.lockId, l.id lid, l.lockName
          from `key` k 
          LEFT JOIN `LOCK` l ON 
          k.lockId = l.id where k.id = #{id}  
      </select>
      <!-- 自定义封装规则:方式一:级联属性封装查出的数据 -->
      <resultMap type="com.luyi.bean.Key" id="mykey">
      	<id property="id" column="kid"/>
      	<result property="keyName" column="keyName"/>
      	<result property="lock.id" column="lid"/>
      	<result property="lock.lockName" column="lockName"/>
      </resultMap>
    
    
      <!-- 自定义封装规则:方式二:association定义联合查询的对象 -->
    <resultMap type="com.luyi.bean.Key" id="mykey">
      	<id property="id" column="kid"/>
      	<result property="keyName" column="keyName"/>
      	<!-- 接下来的属性是一个对象,自定义这个对象分封装规则,使用association:表示联合了一个对象 -->
      	<!-- javaType:指定这个属性的类型 -->
      	<association property="lock" javaType="com.luyi.bean.Lock">
      		<result property="id" column="lid"/>
      		<result property="lockName" column="lockName"/>
      	</association>
    </resultMap>
    
    
    
    </mapper>
    

    properties文件(dbconfig):

    username=root
    password=123
    jdbcurl=jdbc:mysql://localhost:3306/my?serverTimezone=UTC
    driverclass=com.mysql.cj.jdbc.Driver
    

    全局配置文件:

    <!--mybatis-config.xml-->
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
      PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
      <properties resource="dbconfig.properties"></properties>
      <environments default="development">
        <environment id="development">
          <transactionManager type="JDBC"/>
          <!--properties属性引入properties配置文件 -->
          <dataSource type="POOLED">
            <property name="driver" value="${driverclass}"/>
            <property name="url" value="${jdbcurl}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
          </dataSource>
        </environment>
      </environments>
      <mappers>
        <mapper resource="KeyDao.xml"/>
      </mappers>
    </configuration>
    

    测试文件(Test01.java):

    package com.luyi.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    import junit.framework.TestCase;
    
    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 com.luyi.bean.Key;
    import com.luyi.dao.KeyDao;
    
    public class Test01 extends TestCase {
    	public SqlSessionFactory initSqlSessionFactory() throws IOException{
    		String resource = "mybatis-config.xml";
    		InputStream inputStream = Resources.getResourceAsStream(resource);
    		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    		return sqlSessionFactory;
    	}
    	public void test01() throws IOException{
    		SqlSession openSession = initSqlSessionFactory().openSession();
    		try {
    			KeyDao mapper = (KeyDao) openSession.getMapper(KeyDao.class);
    			Key key = mapper.getKeyById(1);
    			System.out.println(key);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			openSession.close();
    		}
    	}
    }
    

    联合查询(1对多)

    在联合查询(1对1)的代码实现基础上进行一下修改:

    Lock.java:

    package com.luyi.bean;
    
    import java.util.List;
    
    
    public class Lock {
    	private Integer id;
    	private String lockName;
    	private List<Key> keys;
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public String getLockName() {
    		return lockName;
    	}
    	public void setLockName(String lockName) {
    		this.lockName = lockName;
    	}
    	
    	public List<Key> getKeys() {
    		return keys;
    	}
    	public void setKeys(List<Key> keys) {
    		this.keys = keys;
    	}
    	@Override
    	public String toString() {
    		return "Lock [id=" + id + ", lockName=" + lockName + ", keys=" + keys
    				+ "]";
    	}
    }
    

    LockDao.java:

    package com.luyi.dao;
    
    import com.luyi.bean.Lock;
    
    public interface LockDao {
    
    	//查询锁时把所有的钥匙也查询出来
    	public Lock getLockById(int id);
    }
    

    LockDao.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">
    <mapper namespace="com.luyi.dao.LockDao">
      <select id="getLockById" resultMap="myLock">
        select k.id kid, k.keyName, k.lockId, l.id lid, l.lockName
          from `key` k 
          LEFT JOIN `LOCK` l ON 
          k.lockId = l.id where l.id = #{id}  
      </select>
      <!-- 自定义封装规则,collection标签定义集合类型分封装 -->
      <resultMap type="com.luyi.bean.Lock" id="myLock">
      	<id property="id" column="lid"/>
      	<result property="lockName" column="lockName"/>
      	<!-- collection:定义集合元素的封装
      	propertype="":指定哪个属性是集合属性
      	ofType="":指定集合里面元素的类型 -->
      	<collection property="keys" ofType="com.luyi.bean.Key">
      		<!-- 标签体中指定集合中这个元素的封装规则 -->
      		<id property="id" column="kid"/>
      		<result property="keyName" column="keyName"/>
      	</collection>
      </resultMap>
    </mapper>
    

    测试文件:Test01.java:

    package com.luyi.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    import junit.framework.TestCase;
    
    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 com.luyi.bean.Key;
    import com.luyi.bean.Lock;
    import com.luyi.dao.KeyDao;
    import com.luyi.dao.LockDao;
    
    public class Test01 extends TestCase {
    	public SqlSessionFactory initSqlSessionFactory() throws IOException{
    		String resource = "mybatis-config.xml";
    		InputStream inputStream = Resources.getResourceAsStream(resource);
    		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    		return sqlSessionFactory;
    	}
    	
    	public void test02() throws IOException{
    		SqlSession openSession = initSqlSessionFactory().openSession();
    		try {
    			LockDao mapper =  openSession.getMapper(LockDao.class);
    			Lock lock = mapper.getLockById(3);
    			System.out.println(lock);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			openSession.close();
    		}
    	}
    }
    

    联合查询(association分步查询)

    代码实现(在联合查询(1对多)的代码实现上进行修改):

    KeyDao.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">
    <mapper namespace="com.luyi.dao.KeyDao">
      <select id="getKeyById" resultMap="mykey">
          select * from `key` where id = #{id}
      </select>
      <!-- 自定义封装规则,association定义联合查询的对象 -->
      <resultMap type="com.luyi.bean.Key" id="mykey">
      	<id property="id" column="kid"/>
      	<result property="keyName" column="keyName"/>
      	<!-- 告诉mybatis自己去调用一个查询查询锁
      	select="":指定一个查询sql的唯一标识,mybatis自动调用指定的sql将查出的lock封装进来
      	column:指定将哪一列的数据传递过去
      	 -->
      	<association property="lock" 
      	select="com.luyi.dao.LockDao.getLockById"
      	column="id"
      	 >
      	</association>
      </resultMap>
    </mapper>
    

    LockDao.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">
    <mapper namespace="com.luyi.dao.LockDao">
      <select id="getLockById" resultType="com.luyi.bean.Lock" > 
          select * from `lock` where id = #{id}
      </select>
    
    </mapper>
    

    注意:测试方法使用的是test01方法测试;

    联合查询(按需加载和延迟加载)

    按需加载的配置:

    <settings>
    	<!-- 开启延迟加载 -->
    	<setting name="lazyLoadingEnabled" value="true"/>
    	<!-- 开启属性按需加载 -->
    	<setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    

    注意:设置了按需加载的配置之后,使用分步查询时,不会马上两条查询语句都发出去,而是按需加载,当我们需要使用另一个bean的属性时,才发送查询语句过去查询获取这个属性

    联合查询(collection分步查询延迟加载):

    代码实现:

    所有的bean文件:

    //Key.java
    
    package com.luyi.bean;
    
    public class Key {
    	private Integer id;
    	private String keyName;
    	private Lock lock;
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public String getKeyName() {
    		return keyName;
    	}
    	public void setKeyName(String keyName) {
    		this.keyName = keyName;
    	}
    	public Lock getLock() {
    		return lock;
    	}
    	public void setLock(Lock lock) {
    		this.lock = lock;
    	}
    	public String toString() {
    		return "Key [id=" + id + ", keyName=" + keyName + ", lock=" + lock
    				+ "]";
    	}
    	
    }
    
    //Lock.java
    
    package com.luyi.bean;
    
    import java.util.List;
    
    
    public class Lock {
    	private Integer id;
    	private String lockName;
    	private List<Key> keys;
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public String getLockName() {
    		return lockName;
    	}
    	public void setLockName(String lockName) {
    		this.lockName = lockName;
    	}
    	
    	public List<Key> getKeys() {
    		return keys;
    	}
    	public void setKeys(List<Key> keys) {
    		this.keys = keys;
    	}
    	@Override
    	public String toString() {
    		return "Lock [id=" + id + ", lockName=" + lockName + ", keys=" + keys
    				+ "]";
    	}
    }
    

    所有的dao文件:

    //KeyDao.java
    package com.luyi.dao;
    
    import java.util.List;
    
    import com.luyi.bean.Key;
    
    public interface KeyDao {
    	public Key getKeyById(int id);
    	public List<Key> getKeyByLockId(int id);
    }
    
    //LockDao.java
    
    package com.luyi.dao;
    
    import com.luyi.bean.Lock;
    
    public interface LockDao {
    
    	//查询锁时把所有的钥匙也查询出来
    	public Lock getLockById(int id);
    }
    

    配置文件:

    dbconfig.properties:

    username=root
    password=123
    jdbcurl=jdbc:mysql://localhost:3306/my?serverTimezone=UTC
    driverclass=com.mysql.cj.jdbc.Driver
    

    mybatis-config.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
      PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-config.dtd">
      
    <configuration>
    
      <properties resource="dbconfig.properties"></properties>
      <settings>
    		<!-- 开启延迟加载 -->
    		<setting name="lazyLoadingEnabled" value="true"/>
    		<!-- 开启属性按需加载 -->
    		<setting name="aggressiveLazyLoading" value="false"/>
    	</settings>
      <environments default="development">
        <environment id="development">
          <transactionManager type="JDBC"/>
          <!--properties属性引入properties配置文件 -->
          <dataSource type="POOLED">
            <property name="driver" value="${driverclass}"/>
            <property name="url" value="${jdbcurl}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
          </dataSource>
        </environment>
      </environments>
      <mappers>
        <mapper resource="KeyDao.xml"/>
        <mapper resource="LockDao.xml"/>
      </mappers>
    </configuration>
    

    log4j.xml:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
     
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
     
     <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
       <param name="Encoding" value="UTF-8" />
       <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m  (%F:%L) 
    " />
       </layout>
     </appender>
     <logger name="java.sql">
       <level value="debug" />
     </logger>
     <logger name="org.apache.ibatis">
       <level value="info" />
     </logger>
     <root>
       <level value="debug" />
       <appender-ref ref="STDOUT" />
     </root>
    </log4j:configuration>
    

    KeyDao.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">
    <mapper namespace="com.luyi.dao.KeyDao">
    	
      <select id="getKeyByLockId" resultType="com.luyi.bean.Key">
      	select * from `key` where lockId = #{id}
      </select>
      <select id="getKeyById" resultMap="mykey">
          select * from `key` where id = #{id}
      </select>
      <!-- 自定义封装规则,association定义联合查询的对象 -->
      <resultMap type="com.luyi.bean.Key" id="mykey">
      	<id property="id" column="kid"/>
      	<result property="keyName" column="keyName"/>
      	<!-- 告诉mybatis自己去调用一个查询查询锁
      	select="":指定一个查询sql的唯一标识,mybatis自动调用指定的sql将查出的lock封装进来
      	column:指定将哪一列的数据传递过去
      	 -->
      	<association property="lock" 
      	select="com.luyi.dao.LockDao.getLockById"
      	column="id"
      	 >
      	</association>
      </resultMap>
    </mapper>
    
    LockDao.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">
    <mapper namespace="com.luyi.dao.LockDao">
      <select id="getLockById" resultMap="myLock"  > 
          select * from `lock` where id = #{id}
      </select>
      <!-- collection分布查询 -->
      <resultMap type="com.luyi.bean.Lock" id="myLock">
      	<id property="id" column="id"/>
      	<result property="lockName" column="lockName"/>
      	<collection property="keys" 
      	select="com.luyi.dao.KeyDao.getKeyByLockId"
      	column="id">
      		
      	</collection>
      </resultMap>
      
    </mapper>
    

    测试文件(Test01.java):

    package com.luyi.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    import junit.framework.TestCase;
    
    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 com.luyi.bean.Key;
    import com.luyi.bean.Lock;
    import com.luyi.dao.KeyDao;
    import com.luyi.dao.LockDao;
    
    public class Test01 extends TestCase {
    	public SqlSessionFactory initSqlSessionFactory() throws IOException{
    		String resource = "mybatis-config.xml";
    		InputStream inputStream = Resources.getResourceAsStream(resource);
    		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    		return sqlSessionFactory;
    	}
    	public void test01() throws IOException{
    		SqlSession openSession = initSqlSessionFactory().openSession();
    		try {
    			KeyDao mapper = (KeyDao) openSession.getMapper(KeyDao.class);
    			Key key = mapper.getKeyById(1);
    			System.out.println(key.getLock().getLockName());
    			Thread.sleep(3000);
    			System.out.println(key.getKeyName());
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			openSession.close();
    		}
    	}
    	
    	public void test02() throws IOException{
    		SqlSession openSession = initSqlSessionFactory().openSession();
    		try {
    			LockDao mapper =  openSession.getMapper(LockDao.class);
    			Lock lock = mapper.getLockById(3);
    			System.out.println(lock.getLockName());
    			System.out.println(lock.getKeys());
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			openSession.close();
    		}
    	}
    }
    

    6.动态sql

    概述:方便了我们拼接数据库表字符

    第一个动态sql程序:

    环境部署:

    代码实现:

    bean文件:

    //Teacher.java
    package com.luyi.bean;
    
    import java.util.Date;
    
    public class Teacher {
    	private Integer id;
    	private String teacherName;
    	private String address;
    	private Date birth;
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public String getTeacherName() {
    		return teacherName;
    	}
    	public void setTeacherName(String teacherName) {
    		this.teacherName = teacherName;
    	}
    	public String getAddress() {
    		return address;
    	}
    	public void setAddress(String address) {
    		this.address = address;
    	}
    	public Date getBirth() {
    		return birth;
    	}
    	public void setBirth(Date birth) {
    		this.birth = birth;
    	}
    	@Override
    	public String toString() {
    		return "Teacher [id=" + id + ", teacherName=" + teacherName
    				+ ", address=" + address + ", birth=" + birth + "]";
    	}
    	
    	
    }
    

    dao文件:

    //TeacherDao.java
    package com.luyi.dao;
    
    import com.luyi.bean.Teacher;
    
    public interface TeacherDao {
    	public Teacher getTeacherByCondition(Teacher teacher);
    }
    

    SQL映射文件(TeacherDao.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">
    <mapper namespace="com.luyi.dao.TeacherDao">
      <select id="getTeacherByCondition" resultType="com.luyi.bean.Teacher">
        select * from Teacher where
        <!-- if标签判断条件进行sql拼接 -->
        <if test="id!=null">
        	id > #{id} 
        </if>
        <if test="teacherName != null and teacherName != ''">
        	and teacherName like #{teacherName}
        </if>
        <if test="birth != null">
        	and birth &lt; #{birth}
        </if>
      </select>
    </mapper>
    

    dbconfig.properties:

    username=root
    password=123
    jdbcurl=jdbc:mysql://localhost:3306/my?serverTimezone=UTC
    driverclass=com.mysql.cj.jdbc.Driver
    

    mybtais-config.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
      PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-config.dtd">
      
    <configuration>
    
      <properties resource="dbconfig.properties"></properties>
      <settings>
    		<!-- 开启延迟加载 -->
    		<setting name="lazyLoadingEnabled" value="true"/>
    		<!-- 开启属性按需加载 -->
    		<setting name="aggressiveLazyLoading" value="false"/>
    	</settings>
      <environments default="development">
        <environment id="development">
          <transactionManager type="JDBC"/>
          <!--properties属性引入properties配置文件 -->
          <dataSource type="POOLED">
            <property name="driver" value="${driverclass}"/>
            <property name="url" value="${jdbcurl}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
          </dataSource>
        </environment>
      </environments>
      <mappers>
        <mapper resource="TeacherDao.xml"/>
      </mappers>
    </configuration>
    

    测试文件(Test01.java):

    package com.luyi.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Date;
    
    import junit.framework.TestCase;
    
    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 com.luyi.bean.Teacher;
    import com.luyi.dao.TeacherDao;
    
    public class Test01 extends TestCase {
    	public SqlSessionFactory initSqlSessionFactory() throws IOException{
    		String resource = "mybatis-config.xml";
    		InputStream inputStream = Resources.getResourceAsStream(resource);
    		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    		return sqlSessionFactory;
    	} 
    	public void test01() throws IOException{
    		SqlSession openSession = initSqlSessionFactory().openSession();
    		try {
    			TeacherDao teacherDao = openSession.getMapper(TeacherDao.class);
    			Teacher teacher = new Teacher();
    			teacher.setId(1);
    			teacher.setTeacherName("赵%%");
    			teacher.setBirth(new Date());
    			System.out.println(teacher);
    			Teacher result = teacherDao.getTeacherByCondition(teacher);
    			System.out.println(result);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			openSession.close();
    		}
    	}
    }
    

    补充:where标签可以替代where关键字,帮我们去除写在前面的and,防止报错,如:

     <select id="getTeacherByCondition" resultType="com.luyi.bean.Teacher">
        select * from Teacher 
       <where>
       	 <!-- if标签判断条件进行sql拼接 -->
        <if test="id!=null">
        	and id > #{id} 
        </if>
        <if test="teacherName != null and teacherName != ''">
        	and teacherName like #{teacherName} 
        </if>
        <if test="birth != null">
        	and birth &lt; #{birth} 
        </if>
       </where>
      </select>
    

    trim标签的使用:

    trim截取字符串:

    • prefix="":前缀,为我们下面的sql整体添加一个前缀
    • prefixOverrides="" :取出整体字符串前面多余的字符
    • suffix="":为整体添加一个后缀
    • suffixOverrides="":后面哪个多了可以去掉

    代码示例:

      <select id="getTeacherByCondition" resultType="com.luyi.bean.Teacher">
        select * from Teacher 
        <!-- trim截取字符串:
        	 prefix="":前缀,为我们下面的sql整体添加一个前缀
        	 prefixOverrides="" :取出整体字符串前面多余的字符
        	 suffix="":为整体添加一个后缀
        	 suffixOverrides="":后面哪个多了可以去掉
         -->
      	<trim prefix="where" prefixOverrides="and"  suffixOverrides="and">
    	 	<!-- if标签判断条件进行sql拼接 -->
    	    <if test="id!=null">
    	    	and id > #{id} 
    	    </if>
    	    <if test="teacherName != null and teacherName != ''">
    	    	and teacherName like #{teacherName} 
    	    </if>
    	    <if test="birth != null">
    	    	and birth &lt; #{birth} 
    	    </if>
      	</trim>
      </select>
    

    foreach标签的使用

    foreach标签遍历集合:

    • collection="":指定要遍历的集合的key
    • close="":以什么作为结束符号
    • index="i" :索引,
      • 如果遍历的是一个list:index,指定的变量保存当前索引;
      • 如果遍历的是一个map,index指定的变量就是保存了当前遍历的key
    • item="变量名":每次遍历出的元素起一个变量名方便引用
    • open="":以什么作为开始符号
    • separator="":每次遍历的元素的分隔符

    代码示例(在动态sql的第一个程序案例的基础上进行修改):

    TeacherDao.java:

    package com.luyi.dao;
    
    
    
    import java.util.List;
    
    import org.apache.ibatis.annotations.Param;
    
    import com.luyi.bean.Teacher;
    
    public interface TeacherDao {
    	public Teacher getTeacherByCondition(Teacher teacher);
    	public List<Teacher> getTeachersByids(@Param("ids")List<Integer> ids);
    }
    

    TeacherDao.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">
    <mapper namespace="com.luyi.dao.TeacherDao">
      <select id="getTeacherByCondition" resultType="com.luyi.bean.Teacher">
        select * from Teacher 
        <!-- trim截取字符串:
        	 prefix="":前缀,为我们下面的sql整体添加一个前缀
        	 prefixOverrides="" :取出整体字符串前面多余的字符
        	 suffix="":为整体添加一个后缀
        	 suffixOverrides="":后面哪个多了可以去掉
         -->
      	<trim prefix="where" prefixOverrides="and"  suffixOverrides="and">
    	 	<!-- if标签判断条件进行sql拼接 -->
    	    <if test="id!=null">
    	    	and id > #{id} 
    	    </if>
    	    <if test="teacherName != null and teacherName != ''">
    	    	and teacherName like #{teacherName} 
    	    </if>
    	    <if test="birth != null">
    	    	and birth &lt; #{birth} 
    	    </if>
      	</trim>
      </select>
    
      <select id="getTeachersByids" resultType="com.luyi.bean.Teacher">
      	select * from teacher where id in 
      	<!-- 
      		 collection="":指定要遍历的集合的key 
      		 close="":以什么作为结束符号
     		 index="i" :索引,
     		 如果遍历的是一个list:index,指定的变量保存当前索引;
     		 如果遍历的是一个map,index指定的变量就是保存了当前遍历的key
     		 item="变量名":每次遍历出的元素起一个变量名方便引用
     		 open="":以什么作为开始符号
     		 separator="":每次遍历的元素的分隔符
      	 -->
      	<foreach collection="ids" close=")" index="" item="id_item" open="(" separator=",">
      		#{id_item}
      	</foreach>
      </select>
    
    </mapper>
    

    Test01.java:

    package com.luyi.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Arrays;
    import java.util.Date;
    import java.util.List;
    
    import junit.framework.TestCase;
    
    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 com.luyi.bean.Teacher;
    import com.luyi.dao.TeacherDao;
    
    public class Test01 extends TestCase {
    	public SqlSessionFactory initSqlSessionFactory() throws IOException{
    		String resource = "mybatis-config.xml";
    		InputStream inputStream = Resources.getResourceAsStream(resource);
    		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    		return sqlSessionFactory;
    	} 
    	/**
    	 * 测试第一个动态sql程序
    	 * @throws IOException
    	 */
    	public void test01() throws IOException{
    		SqlSession openSession = initSqlSessionFactory().openSession();
    		try {
    			TeacherDao teacherDao = openSession.getMapper(TeacherDao.class);
    			Teacher teacher = new Teacher();
    			teacher.setId(1);
    			//teacher.setTeacherName("赵%%");
    			teacher.setBirth(new Date());
    			System.out.println(teacher);
    			Teacher result = teacherDao.getTeacherByCondition(teacher);
    			System.out.println(result);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			openSession.close();
    		}
    	}
    	
    	/**
    	 * 测试foreach标签的使用
    	 * @throws IOException
    	 */
    	public void test02() throws IOException{
    		SqlSession openSession = initSqlSessionFactory().openSession();
    		try {
    			TeacherDao teacherDao = openSession.getMapper(TeacherDao.class);
    			List<Integer> list = Arrays.asList(1, 2, 3);
    			List<Teacher> result = teacherDao.getTeachersByids(list);
    			System.out.println(result);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			openSession.close();
    		}
    	}
    }
    

    choose标签的使用

    概述:choose标签中当when条件满足时,就不会往下走了

    代码实现:

    <trim prefix="where" prefixOverrides="and"  suffixOverrides="and">
    	<choose>
    		<when test="id != null">
    			id=#{id} and
    		</when>
    		<when test="teacherName != null and teacherName != ''">
    			teacherName like teacherName and
    		</when>
    		<when test="birth != null">
    			birth &lt; #{birth}
    		</when>
    		<otherwise>
    			1=1
    		</otherwise>
    	</choose>
    </trim>
    

    set标签结合if标签完成mybatis动态更新

    概述:set替代了set关键字,并可以去除多余的逗号

    代码实现:

    <select id="updateTeacher" resultType="com.luyi.bean.Teacher">
    	UPDATE teacher 
    	<!-- set替代了set关键字,并可以去除多余的逗号 -->
    	<set>
    		<if test="teacherName != null and teacherName != ''">
    			teacherName=#{teacherName},
    		</if>
    		<if test="address != null and address != ''">
    			address = #{address},
    		</if>
    		<if test="birth != null">
    			birth = #{birth},
    		</if>
    	</set>
    	where id = #{id}
    </select>
    

    其他标签

    1.bind标签:把一个表达式绑定到一个变量上

    2.sql标签:抽取出可重用的sql语句

    OGNL的介绍

    OGNL(Object Graph Navigation Language),也就是对象导航图语言,这是一种强大的
    表达式语言,通过它可以非常方便的来操作对象属性,使用方法就是级联属性一级一级往下调用即可

    其他两个参数:

    概述:在mybatis中,传入的参数可以用来做判断,额外还有两个参数_parameter和_databaseId

    • _parameter:代表传进来的参数

      • 传入了单个参数,_parameter就代表这个参数
      • 传入了多个参数,_parameter就代表多个参数集合起来的map
    • _databaseId:代表当前环境,如果配置了databaseIdProvider,_databaseId就有值

    7.缓存机制(用Map保存查询出来的一些数据)

    概述:MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。

    MyBatis系统中默认定义了两级缓存(一级缓存和二级缓存):

    • 默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启。
    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
    • 为了提高扩展性。MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

    一级缓存(默认存在)

    概述:只要之前查询过的数据,mybatis就会保存在一个缓存中(Map);下次获取直接从缓存中拿,需要注意的是一级缓存是sqlSession级别的缓存,sqlSession关闭或者提交以后,一级缓存的数据就会放在二级缓存中

    一级缓存失效的几种情况:

    1.不同的sqlSession使用不同的一级缓存

    • 只有在同一个sqlSession期间查询到的数据会保存在这个sqlSession的缓存中,下次使用这个sqlSession查询会从缓存中拿

    2.同一个方法,不同的参数,由于可能之前没查询过,所以还会发新的sql

    3.在这个sqlSession期间,如果有增删改操作,就会清空之前的缓存

    4.手动清空缓存:通过openSession.clearCache()方法清空

    二级缓存

    概述:全局作用域缓存,二级缓存默认不启动,需要手动配置,MyBatis提供二级缓存的接口以及实现,缓存实现要求POJO实现Serializable接口,二级缓存在sqlSession关闭或提交之后才生效;二级缓存是namespace级别的缓存,说它是namespace级别的缓存是因为使用二级缓存的映射文件处需要使用chache标签进行配置,而这个映射文件映射的就是namespace指定的类

    步骤:

    • 全局配置文件中开启二级缓存:<setting name="cacheEnabled" value="true"/>

    • 需要使用二级缓存的映射文件处使用cache配置缓存:<cache><cache/>

    • POJO需要实现Serializable接口

    缓存的相关属性(了解)

    概述:缓存的相关属性,也就是cache标签里面的属性

    • eviction=“FIFO”:缓存回收策略:
      LRU – 最近最少使用的:移除最长时间不被使用的对象。
    • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
    • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
    • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
      默认的是 LRU。
    • flushInterval:刷新间隔,单位毫秒
      默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
    • size:引用数目,正整数
      代表缓存最多可以存储多少个对象,太大容易导致内存溢出
    • readOnly:只读,true/false
      true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
      false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。

    缓存的查询顺序

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

    • 二级缓存中,一级缓存关闭了就有了
    • 一级缓存中,二级缓存中没有此数据,就会看一级缓存,一级缓存没有去查数据库,数据库的查询后的结果放在一级缓存中

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

    缓存有关设置

    • 全局setting的cacheEnable:
      配置二级缓存的开关。一级缓存一直是打开的。
    • select标签的useCache属性:
      配置这个select是否使用二级缓存。一级缓存一直是使用的
    • sql标签的flushCache属性:
      增删改默认flushCache=true。sql执行以后,会同时清空一级和二级缓存。查询默认flushCache=false。
    • sqlSession.clearCache():
      只是用来清除一级缓存。
    • 当在某一个作用域 (一级缓存Session/二级缓存Namespaces) 进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。

    整合第三方缓存

    概述:MyBatis自带的缓存的功能没有很强大,往往需要整合进其他一些优秀的缓存来进行MyBatis缓存的使用,我们可以通过Cache接口实现整合第三方缓存

    下面我们通过整个EhCache来介绍整合第三方缓存的步骤:

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

    MyBatis定义了Cache接口方便我们进行自定义扩展。
    步骤:

    • 导入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
    • 编写ehcache.xml配置文件
    • 配置cache标签
    • 参照缓存:若想在命名空间中共享相同的缓存配置和实例。可以使用 cache-ref 元素来引用另外一个缓存。
  • 相关阅读:
    全角 半角转换 .net
    [下载]微软Windows命令行PowerShell 2.0
    logstash收集java程序日志
    使用filebeat替代logstash收集日志
    Kibanna图形统计
    MySQL Blind Sql Injection
    超级后门泄露版
    HACKING WITH JAVASCRIPT
    Exploiting Common Vulnerabilities in PHP Applications
    3389安全记录批处理
  • 原文地址:https://www.cnblogs.com/luyi001/p/13631087.html
Copyright © 2020-2023  润新知