MyBatis框架课堂笔记

MyBatis

轻量级的持久层的开源框架,对JDBC进行了完美的封装,是一个不完全的ORM映射框架

1. 基本内容
  • MyBatis 简介

    1. 轻量级:不依赖于应用服务器(Tomcat),可以单独运行或执行的框架

    2. 持久层(数据访问层):实现对数据的操作,类似于Dao层

    3. ORM:对象关系映射(O:对象; R:关系数据库中的表; M:映射<一一对应的关系>)

      63D93A599C14B2B35170C85F331FA18A

    4. 不完全的映射:只能实现输入参数和输出结果的映射,不能实现sql的自动映射

  • MyBatis 作用

    MyBatis 就是对数据库中的数据进行操作的一个框架,充当了项目中的数据访问层的角色

  • MyBatis的执行流程

QQ20190609-0

2. MyBatis 用法
  • 基本步骤

    1. 创建一个java项目,导入mybatis的相关jar包,数据库驱动包

    2. 创建一个和src同目录的资源文件夹(config)

      在config文件夹下创建一个全局配置文件 SqlMapConfig.xml

    注意:每一个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>
    
    		<!-- 临时采用jdbc提供的数据源连接池-->
    		<environments default="development">
    			<environment id="development">
    			<!-- 使用jdbc事务管理-->
    				<transactionManager type="JDBC" />
    			<!-- 数据库连接池-->
    				<dataSource type="POOLED">
    					<property name="driver" value="com.mysql.jdbc.Driver" />
    					<property name="url" value="jdbc:mysql://localhost:3306/girls?characterEncoding=utf-8" />
    					<property name="username" value="root" />
    					<property name="password" value="uesrroot" />
    				</dataSource>
    			</environment>
    		</environments>	
    		<!-- 加载mapper映射文件到全局配置文件
    			mappers:可以加载多个mapper文件
    			mapper:具体哪一个mapper文件
    			resource:指定mapper文件的针对全局文件的相对路径
    		 -->
    		<mappers>
    			<mapper resource="AdminMapper.xml"/>
    		</mappers>
    </configuration>
    
    1. 在config下创建一个mybatis配置文件

      实现对sql语句的管理以及sql语句中查询语句和查询结果的映射关系配置

      标签总结:

      1. mapper标签:是映射文件的根标签,一个映射文件只能有一个mapper标签,有开始标签和结束标签
      2. namesapace:命名空间,主要是对sql语句进行隔离,方便管理。但是如果使用mapper动态代理开发,namespace就有特殊的含义了,是xml的全路径名
      3. select:用于查询的标签
      4. id:当前sql语句的唯一标识,相当于给sql语句起名字
      5. resultType:sql语句查询出单条结果要映射的对象类型,类型必须是全路径名,包名+类名;在xml文件中设置别名之后,可以用首字母小写的别名
      6. " #{} ”:相当于jdbc中的?,{}中传递的参数就是sql条件对应的参数名
      7. " ${} ”:进行值的拼接,如果传递的值是基本值类型,那么{}中必须是value,相当于把条件直接拼接到sql语句中,容易引起sql注入的问题
      8. keyProperty:查询到的自增主键映射到输入参数对象的哪个属性上
      9. order:执行新增语句之后,再去执行当前查询自增主键的函数
      10. resultType:当前查询自增id返回的类型
       <?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">
      <!-- mybatis配置文件,实现对sql语句的管理以及sql语句中查询语句和查询结果的映射关系配置 
      	 mapper标签:是映射文件的根标签,一个映射文件只能有一个mapper标签,有开始标签和结束标签
      	 namesapace:命名空间,主要是对sql语句进行隔离,方便管理,但是如果使用mapper动态代理开发,
      	 namespace就有特殊的含义了,是xml的全路径名
      -->
      <mapper namespace="test">
      	...
      </mapper>
      
      • 查询所有的用户信息

        <!-- 查询所有用户信息 -->
        <!-- 配置 查询所有用户信息的 配置文件 
        		select:用于查询的标签
        		id:当前sql语句的唯一标识,相当于给sql语句起名字
        		resultType:sql语句查询出单条结果要映射的对象类型,类型必须是全路径名,包名+类名
        	-->	 
        	<select id="findadminlist" resultType="com.pojo.Admin">
        		select * from admin
        	</select>
        
      • 根据id 查询

        <!-- 根据id查询 
        		parameterType:sql传递的条件的值映射的数据类型,输入映射的类型
        		resultType:sql语句查询出单条结果要映射的对象类型,类型必须是全路径名,包名+类名,输出结果映射的类型
        		#{}:相当于jdbc中的?,{}中传递的参数就是sql条件对应的参数名
        	-->
        	<select id="findadminbyid" parameterType="int" resultType="com.pojo.Admin">
        		select * from admin where id = #{id}
        	</select>
        
      • 根据名字模糊查询

        <!-- 根据名字模糊查询 
        		${}:进行值的拼接,如果传递的值是基本值类型,那么{}中必须是value
        		sql条件基本类型参数传递#{}和${}
        		#{}:相当于?,大括号中参数任意
        		${}:相当于把条件直接拼接到sql语句中,容易引起sql注入的问题,{}中参数必须是value
        	-->
        	<select id="findadminbyname" parameterType="String" resultType="com.pojo.Admin">
        		select * from where username like #{name}
        		select * from where username like '%${value}%'
        	</select>
        
      • 根据id删除

        	<!-- 根据id删除 
        		增删改不需要指定结果类型映射(resultType)
        	-->
        	<delete id="deleteadminbyid" parameterType="java.lang.Integer">
        		delete from admin where id = #{id}
        	</delete>
        
      • 新增

        <!-- 新增 -->
        	<insert id="inseradmin" parameterType="com.pojo.Admin">
        	<!-- 通过mysql的一个函数,得到自增主键的值
        		keyProperty:查询到的自增主键映射到输入参数对象的哪个属性上
        		order:执行新增语句之后,再去执行当前查询自增主键的函数
        		resultType:当前查询自增id返回的类型
        	 -->
        		<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
        			select LAST_INSERT_ID()
        		</selectKey>
            
        	<!-- 通过mysql的UUID函数,自行维护主键
        		使用UUID维护主键注意事项:
        			1.主键在数据库中的类型是varchar类型,并且长度大于32
        			2.通过selectKey标签指定,获取UUID的函数
        	 -->
        	 	<!-- <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
        			select UUID()
        		</selectKey> -->
            
        	<!-- 获取oracle序列,实现主键的获取 
        		<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.Integer">
        			select 序列名.nexval()
        		</selectKey>
        	-->
        		insert into admin values(#{id},#{username},#{password})
        	</insert>
        

        通过mysql的UUID函数,自行维护主键

        使用UUID维护主键注意事项:

        1. 主键在数据库中的类型是varchar类型,并且长度大于32
        2. 通过selectKey标签指定,获取UUID的函数
      • 根据id修改

        <!-- 根据id修改 -->
        	<update id="updateadmin" parameterType="com.pojo.Admin">
        		update admin set username=#{username},password=#{password} where id=#{id}
        	</update>
        
      • 总结

        1.<select id="" parameterType="" resultType="">
          	select * from where username like #{name}
        		select * from where username like '%${value}%'
          </select>
          select:用于查询的标签
        	id:当前sql语句的唯一标识,相当于给sql语句起名字
          parameterType:sql传递的条件的值映射的数据类型,输入映射的类型
        	resultType:sql语句查询出单条结果要映射的对象类型,类型必须是全路径名,包名+类名,输出结果映	
        						  射的类型
          #{}:相当于jdbc中的?,{}中传递的参数就是sql条件对应的参数名,大括号中参数任意
          ${}:相当于把条件直接拼接到sql语句中,容易引起sql注入的问题,{}中参数必须是value
        
        2.增删改不需要指定结果类型映射(resultType)
        
        3.新增
        	- 通过mysql的一个函数,得到自增主键的值
        	keyProperty:查询到的自增主键映射到输入参数对象的哪个属性上
        	order:执行新增语句之后,再去执行当前查询自增主键的函数
        	resultType:当前查询自增id返回的类型
        <insert id="inseradmin" parameterType="com.pojo.Admin">
        	<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
        		select LAST_INSERT_ID()
        	</selectKey>
        	insert into admin values(#{id},#{username},#{password})
        </insert>
        
        	- 通过mysql的UUID函数,自行维护主键
        		使用UUID维护主键注意事项:
        			1.主键在数据库中的类型是varchar类型,并且长度大于32
        			2.通过selectKey标签指定,获取UUID的函数
        	 	<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
        			select UUID()
        		</selectKey>
        		...
        
        	- 获取oracle序列,实现主键的获取 
        		<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.Integer">
        			select 序列名.nexval()
        		</selectKey>
        		...
        	
        
    2. 创建一个测试类

      package com.test;
      import java.io.IOException;
      import java.io.InputStream;
      import java.util.List;
      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 org.apache.log4j.lf5.util.Resource;
      import org.junit.Test;
      import com.pojo.Admin;
      public class AdminTest {
      //	查询所有用户的信息
      //	通过添加单元测试注解的方法来进行单元测试
      	@Test
      	public void findadminbyid() throws IOException {
      //		1.通过mubatisResources对象的getResourceAsStream("全局配置文件")方法来加载mybatis全局配置文件,创建一个流对象
      		InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
      //		2.创建一个SqlSessionFactory对象,需要传递一个加载了全局配置文件的流对象
      		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
      //		3.通过SqlSessionFactory工厂对象,创建SqlSession对象
      		SqlSession sqlSession = sqlSessionFactory.openSession();
      //		4.通过sqlSession对象,实现增删改查的操作
      		List<Admin> admininfo = sqlSession.selectList("findadminbyid");
      //		5.打印结果
      		System.out.println(admininfo);
      //		6.关闭资源
      		sqlSession.close();
      	}
        
        @Test
      	public void findadminbyid() throws IOException {
      		InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
      		SqlSessionFactory sqlSessionFactory = new 	
          SqlSessionFactoryBuilder().build(inputStream);
      		SqlSession sqlSession = sqlSessionFactory.openSession();
      		Admin admin = sqlSession.selectOne("test.findadminbyid", 6);
      		System.out.println(admin);
      		sqlSession.close();
      	}
        
        @Test
      	public void findadminbyname() throws IOException {
      		InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
      		SqlSessionFactory sqlSessionFactory = new 
          SqlSessionFactoryBuilder().build(inputStream);
      		SqlSession sqlSession = sqlSessionFactory.openSession();
      		List<Admin> admins = sqlSession.selectList("test.findadminbyname");
      		System.out.println(admins);
      		sqlSession.close();
      	}
      	
      	@Test
      	public void deleteadminbyid() throws IOException {
      		InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
      		SqlSessionFactory sqlSessionFactory = new 
          SqlSessionFactoryBuilder().build(inputStream);
      		SqlSession sqlSession = sqlSessionFactory.openSession();
      		int row = sqlSession.delete("test.deleteadminbyid");
      		System.out.println(row);
      		//调用jdbc提供的事务,实现提交操作,使程序中的数据和数据库中的数据保持一致性
      		sqlSession.commit();
      		sqlSession.close();
      	}
      	
      	@Test
      	public void inseradmin() throws IOException {
      		InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
      		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
      		SqlSession sqlSession = sqlSessionFactory.openSession();
      		Admin admin = new Admin();
      		admin.setPassword("9372");
      		admin.setUsername("小李子");
      		int row = sqlSession.insert("test.inseradmin", admin);
      		System.out.println(row);
      		//调用jdbc提供的事务,实现提交操作,使程序中的数据和数据库中的数据保持一致性
      		sqlSession.commit();
      		//查看自增主键的值,意义在于涉及到级联新增(新增部门级联新增一个部门的员工)时,
      		//System.out.println(admin.getId()); 直接通过查看对象的id值,是获取不到自增主键的
      		sqlSession.close();
      	}
      	
      	@Test
      	public void updateadmin() throws IOException {
      		InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
      		SqlSessionFactory sqlSessionFactory = new 
          SqlSessionFactoryBuilder().build(inputStream);
      		SqlSession sqlSession = sqlSessionFactory.openSession();
      		Admin admin = new Admin();
      		admin.setId(12);
      		admin.setPassword("9372");
      		admin.setUsername("小李子");
      		int row = sqlSession.update("test.updateadmin", admin);
      		System.out.println(row);
      		//调用jdbc提供的事务,实现提交操作,使程序中的数据和数据库中的数据保持一致性
      		sqlSession.commit();
      		sqlSession.close();
      	}
        
      }
      
3. 改进
  • Dao
  • DaoImpl 实现类
4. 代理开发
1)Mapper代理的开发模式
  • mapper代理开发 程序员只需要关注接口开发 不需要对实现类进行关注 由mybaits为我们完成具体的数据实现

  • mapper代理开发需要遵循的开发规范

    1. mapper.java接口文件和mapper.xml映射文件同名且在同一包下(UserMapper.java和UserMapper.xml)
    2. 映射文件中的namespace命名空间的值必须是接口文件的全路径名
    3. 接口文件中的方法名必须和映射文件中管理的sql的ID名一致
    4. 接口文件中方法的输入参数的类型必须和映射文件中parameterType指定的类型一致
    5. 接口文件中方法的返回值类型参考映射文件中resultType指定的类型

    Xnip2019-06-16_23-48-19

  • UserMapper.java

    package com.mapper;
    import java.util.List;
    import com.pojo.User;
    public interface UserMapper {
    	//根据id查询
    	public User finduserbyid (int id);
    	//根据姓名模糊查询
    	public List<User> finduserbyname (String username);
    	//新增
    	public boolean insertuser (User user);
    }
    
    
  • UserMapper.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.mapper.UserMapper">
    	<!-- 根据id查询 -->
    	<select id="finduserbyid" parameterType="int" resultType="user">
    		select * from user where id = #{id}
    	</select>
    	<!-- 根据名字查询 -->
    	<select id="finduserbyname" parameterType="String" resultType="user">
    		select * from user where username like '%${value}%'
    	</select>
    	<!-- 新增 -->
    	<insert id="insertuser" parameterType="user">
    		insert into user (username,password) values (#{username},#{password})
    	</insert>
    	<!-- 修改 -->
    	<update id="updateuser" parameterType="user">
    		update user
    	</update>
    </mapper>
    
  • 再建一个test类

    package com.test;
    import java.io.IOException;
    import java.util.List;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    import com.mapper.UserMapper;
    import com.pojo.User;
    import com.until.SqlSessionFactorySingleton;
    public class UserMapperTest {
    	
    	//根据id查询
    	@Test
    	public void usermappertest() throws IOException{
    		//1.得到sqlsession对象
    		SqlSession sqlsession = SqlSessionFactorySingleton.getinstance().openSession();
    		//2.通过sqlsession对象获取mapper接口
    		UserMapper usermapper = sqlsession.getMapper(UserMapper.class);
    		//3.调用接口中对数据库进行操作的方法
    		User user = usermapper.finduserbyid(2);
    		System.out.println(user);	
    	}
    	
    	//姓名模糊查询
    	@Test
    	public void usermappertest2() throws IOException{
    		//1.得到sqlsession对象
    		SqlSession sqlsession = SqlSessionFactorySingleton.getinstance().openSession();
    		//2.通过sqlsession对象获取mapper接口
    		UserMapper usermapper = sqlsession.getMapper(UserMapper.class);
    		//3.调用接口中对数据库进行操作的方法
    		List<User> list = usermapper.finduserbyname("N");
    		System.out.println(list);
    	}
    	
    	//新增
    	@Test
    	public void usermappertest3() throws IOException{
    		//1.得到sqlsession对象
    		SqlSession sqlsession = SqlSessionFactorySingleton.getinstance().openSession();
    		//2.通过sqlsession对象获取mapper接口
    		UserMapper usermapper = sqlsession.getMapper(UserMapper.class);
    		//3.调用接口中对数据库进行操作的方法
    		User user = new User();
    		user.setUsername("Pass");
    		user.setPassword("1234");
    		boolean flag = usermapper.insertuser(user);
    		sqlsession.commit();
    		if(flag) {
    			System.out.println("新增成功");
    		}else {
    			System.out.println("失败");
    		}
    	}
    
    }
    
    
2)ResultType 和 ResultMap
  • ResultType

    作为输出结果映射类型

    sql查询的字段名必须和映射对象的属性名完全一致,这样才能够实现数据的绑定

    一般在单表查询时使用

  • ResultMap (高级映射)

    针对别名映射

    多表连接查询时,指定映射类型

    可以手动绑定查询的字段和映射的结果

    1. 查询的字段手动绑定到映射结果对象类型的步骤:

      • 首先定义一个 <ResultMap> 标签,指定映射结果的对象类型

      • 把查询的字段手动绑定到映射结果对象类型的属性上

    <resultMap type="" id="">	  
    	<id colum="数据库中查出的字段名" property="映射对象的属性名"/>		-- 实现主键的映射
      <result colum="" property=""/>		-- 实现其他普通字段的映射
    </resultMap>
    
    type:当前映射的结果对象类型,你查出的结果要映射到哪个对象类型上
    id:当前resultMap的唯一标识
    
3)动态sql

为了完成对sql语句的一个灵活组装和拼接,实现sql语句根据不同条件查询不同结果的操作。(想查什么就查什么)

主要实现sql条件的一个动态拼接和封装

  • where 标签:包含多个条件,会自动去除第一个条件的and

  • mapper.xml

    <!-- 动态sql实现sql条件的一个动态拼接,
    		提供where动态标签,可以自动包含多个条件,where标签会自动删除第一个条件的and,所以最好加上and
    	 -->
    	 <select id="querybydynamic" parameterType="user" resultType="user">
    	 	select * from user
    	 	<where>
    		 	<if test="username != null and username != ''">
    		 		and username like '%${username}%'
    		 	</if>
    		 	<if test="password != null and password != ''">
    		 		and password = #{password}
    		 	</if>
    	 	</where>
    	 </select>
    
  • sql片段

    重复的动态条件代码抽离出来,形成一个动态的sql片段

    <select id="" parameterType="" resultType="">
    	select count(*) from user
      <where>
      	<include refid="dynamicquery"></include>
      </where>
    </select>
    
5. 多表级联查询
1)分析表结构
2)多表查询建立扩展类,包含所有查询的属性
  • 建立一个拓展类,包含两个实体类的所有属性

  • 查询语句尽量不写 select * from … ,写具体的查询的字段名:

    select orders.id,user_id,number,createtime,note,name,phone,address from orders,user_order where orders.user_id = user_order.id

<select id="findorderanduser" resultType=" ">
		select orders.id,user_id,number,createtime,note,name,phone,address 
		from orders,user_order 
		where orders.user_id = user_order.id
</select>
3)多表级联查询,包装类
  • 一对一

    1. column:数据库查出的字段名
    2. property:实体类里的对象的属性名,映射到对象的属性名
    3. association:把连接查询的用户信息映射到单个用户对象上,一一映射
    4. javaType:映射到对象的类型
    5. Mapper.xml
       <!-- 查询订单级联查询用户的resultMap 一对一 -->
    	<resultMap type="com.pojo.Orders" id="orderanduserresultmap">
    	<!-- column:数据库查出的字段名,property:实体类里的对象的属性名 -->
    		<id column="id" property="orders_id"/>
    		<result column="user_id" property="user_id"/>
    		<result column="number" property="number"/>
    		<result column="createtime" property="createtime"/>
    		<result column="note" property="note"/>
    		<!-- 把连接查询的用户信息映射到单个的用户对象上,一一映射 -->
    		<association property="user" javaType="com.pojo.User">
    			<result column="phone" property="phone"/>
    			<result column="address" property="address"/>
    			<result column="name" property="name"/>
    		</association>
    	</resultMap>
    
    <!-- 查询订单,关联查询订单所属的信息 -->
    	<select id="findorderanduser" resultMap="orderanduserresultmap">
    		select orders.id,user_id,number,createtime,note,name,phone,address 
    		from orders,user_order 
    		where orders.user_id = user_order.id
    	</select>
    
    1. 包装类

      public class Orders {
      	private int orders_id;
      	private int user_id;
      	private String number;
      	private Date createtime;
      	private String note;
      	//包装类
      	private User user;
      
    2. 测试类

    //多表查询,查询订单以及所属的信息
    @Test
    public void orderstest1() throws IOException{
    //1.得到sqlsession对象
    SqlSession sqlsession = SqlSessionFactorySingleton.getinstance().openSession();
    //2.通过sqlsession对象获取mapper接口
    OrdersMapper ordermapper = sqlsession.getMapper(OrdersMapper.class);
    //3.调用接口中对数据库进行操作的方法
    List list = ordermapper.findorderanduser();
    System.out.println(list);
    sqlsession.close();
    }

    
    
    
    
  • 一对多

    1. 需求:查询用户级联查询用户订单信息

    2. collection:把查询的订单信息,映射到包装类中的集合属性上

    3. ofType:指定集合属性的映射类型

    4. Mapper.xml

      <!-- 查询用户级联查询用户的订单信息 一对多 -->
      	<resultMap type="com.pojo.User" id="userandorderresultmap">
      		<id column="id" property="user_id"/>
      		<result column="phone" property="phone"/>
      		<result column="address" property="address"/>
      		<result column="name" property="name"/>	
      		<collection property="orders" ofType="com.pojo.Orders">
      			<id column="orders.id" property="orders_id"/>
      			<result column="user_id" property="user_id"/>
      			<result column="number" property="number"/>
      			<result column="createtime" property="createtime"/>
      			<result column="note" property="note"/>
      		</collection>
      	</resultMap>
      
    5. 测试类

      //查询用户级联查询用户的订单信息
      		@Test
      		public void orderstest2() throws IOException{
      			//1.得到sqlsession对象
      			SqlSession sqlsession = SqlSessionFactorySingleton.getinstance().openSession();
      			//2.通过sqlsession对象获取mapper接口
      			OrdersMapper ordermapper = sqlsession.getMapper(OrdersMapper.class);
      			//3.调用接口中对数据库进行操作的方法
      			List<User> list = ordermapper.finduserandorders();
      			System.out.println(list);	
      			sqlsession.close();
      		}
      
  • 多对多

    1. 需求:查询用户,关联查询用户所下的订单,以及订单明细,和商品信息

    2. 注意事项:

      • 没有关系的两张表不能使用包装类

      • 用户表 — 订单表,一对多

        订单表 — 订单明细表,一对多

        订单明细 — 商品,一对一

      • 用户表里可以建立订单类,一对多,list

        订单表里建立订单明细,一对多,list

        订单明细表里建立商品明细,一对一,items

      • resultMap 注意约束文件中规定的 association,collection的顺序

        <mapper namespace="com.mapper.UserMapper">
         <!--四表联查-->
            <resultMap id="userandordersandorderdetailanditemsresultMap" type="com.pojo.User">
                <id column="user_id" property="user_id"></id>
                <result column="user_name" property="name"></result>
                <result column="phone" property="phone"></result>
                <result column="address" property="address"></result>
        				<!-- 用户表里的订单,一对多,collection -->
                <collection property="orders" ofType="com.pojo.Orders">
                    <id column="orders_id" property="orders_id"></id>
                    <result column="number" property="number"></result>
                    <result column="orders_createtime" property="createtime"></result>
                    <result column="note" property="note"></result>
        						<!-- 订单表里的订单明细,一对多,collection -->
                    <collection property="orderdetails" ofType="com.pojo.orderdetail">
                    	<id column="items_id" property="items_id"></id>
                    	<result column="items_num" property="items_num"></result>
        							<!-- 订单明细里的商品,一对一,association -->
                    	<association property="items" javaType="com.pojo.items">
                    		<result column="items_name" property="name"></result>
                   			<result column="price" property="price"></result>
                    		<result column="detail" property="detail"></result>
                    		<result column="items_createtime" property="createtime"></result>
                		</association>
                	</collection>
                </collection>
        
        <!--查询用户,级联查询用户的订单,订单明细,商品信息,四表联查,多对多-->
            <select id="finduserbymany" resultMap="userandordersandorderdetailanditemsresultMap">
                SELECT
                    user_order.id user_id,
                    user_order.`name` user_name,
                    phone,
                    address,
                    orders.id orders_id,
                    orders.number,
                    orders.createtime orders_createtime,
                    orders.note,
                    orderdetail.items_id,
                    orderdetail.items_num,
                    items.`name` items_name,
                    items.price,
                    items.detail,
                    items.createtime items_createtime
                FROM
                    user_order,
                    orders,
                    orderdetail,
                    items
                WHERE
                    user_order.id = orders.user_id AND
                    orders.id = orderdetail.orders_id AND
                    orderdetail.items_id = items.id
            </select>
        </mapper>
        
4)关联查询mybatis思路

QQ20190618-0

6. 懒加载

在多表连接查询时先查询一张表的信息,如果用到了关联表的信息时,这个时候再去查询关联表

当前这样的实现方式可以提高查询效率

  • 需求:查询订单关联查询用户信息实现延迟加载

    实现步骤:

    1. 先创建查询订单的sql语句(查订单单表)

      <!-- 懒加载 -->
      <select id="findorderbylazy" resultMap="findorderbylazy">
         select * from orders
      </select>
      
    2. 再创建根据订单表中的用户id查询订单关联的用户信息的sql

      <select id="finduserbylazy" resultType="com.pojo.User" parameterType="int">
         select  
          	user_order.id user_id,
          	user_order.`name`,
            phone,
            address
         from
            user_order
         where
            id = #{id}
      </select>
      
    3. 给查询订单的sql标签中创建resultmap结果映射通过association或者collection标签设置延迟加载

      <resultMap type="orders" id="findorderbylazy">
      		<id column="id" property="orders_id"/>
      		<result column="user_id" property="user_id"/>
      		<result column="number" property="number"/>
      		<result column="createtime" property="createtime"/>
      		<result column="note" property="note"/>
         	<!--
      			select:指定延迟加载需要加载的sql语句
       			column:根据外键进行两表关联查询
      		--> 
      		<association property="user" javaType="com.pojo.User" select="finduserbylazy" 			column="user_id"></association>
      </resultMap>
      
    4. 在mybatis全局配置文件中通过setting标签设置开启延迟加载的命令

      <!-- 懒加载 -->
      <settings>
      		< !-- 开启延迟加载的配置 -->
      		<setting name="lazyLoadingEnabled" value="true"/>
      		<!-- 设置加载方式为懒加载 -->
      		<setting name="aggressiveLazyLoading" value="false"/>
      </settings>
      
7. 缓存
1)一级缓存
  • where 数据库中的字段名 = #{实体类中的属性名} ,必须对应起来

  • 查询的数据库的结果的字段名必须和实体类中的属性名相对应

  • UserMapper.xml

    <!-- 缓存测试 -->
        <!--  where 数据库中的字段名 = #{实体类中的属性名} ,必须对应起来
        	查询的数据库的结果的字段名必须和实体类中的属性名相对应
        -->
        <select id="finduserbyid" parameterType="int" resultType="user">
        	select user_order.id user_id,user_order.name,user_order.phone,user_order.address from user_order where id = #{user_id}
        </select>
        
        <!-- 缓存测试,更改 -->
        <update id="updateuser" parameterType="user">
        	update user_order set name=#{name},phone=#{phone},address=#{address} where id=#{user_id}
        </update>
    
    
  • UserMapperTest.java

    //一级缓存测试
        @Test
        public void usertest3() throws IOException {
        	SqlSession sqlSession = SqlSessionFactorySingleton.getinstance().openSession();
        	UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        	
        	//第一次查询
        	User user = userMapper.finduserbyid(2);
        	System.out.println(user);
        	
        	//第一次查询之后更改
        	user.setName("Pack");
        	userMapper.updateuser(user);
        	sqlSession.commit();;
        	
        	//第二次查询
        	User user2 = userMapper.finduserbyid(2);
        	System.out.println(user2);
        	
        	sqlSession.close();
        }
    
2)二级缓存
  • mapper的缓存

  • SqlMapConfig.xml

    <!-- 懒加载 -->
    	<settings>
    		<!-- 开启延迟加载的配置 -->
    		<setting name="lazyLoadingEnabled" value="true"/>
    		<!-- 设置加载方式为懒加载 -->
    		<setting name="aggressiveLazyLoading" value="false"/>
        
    		<!-- 二级缓存开启 -->
    		<setting name="cacheEnabled" value="true"/>
    	</settings>
    
    
  • UserMapper.xml

    	<!-- 二级缓存的开启 -->
    	<cache></cache>
    
  • pojo实现序列化接口

    public class User implements Serializable{
    	
    	private int user_id;
    	private String name;
    	private String phone;
    	private String address;
    	
    
  • UserMapperTest.java

    //二级缓存的测试
        //(mapper缓存)
        @Test
        public void usertest4() throws IOException {
        	SqlSession sqlSession1 = SqlSessionFactorySingleton.getinstance().openSession();
        	SqlSession sqlSession2 = SqlSessionFactorySingleton.getinstance().openSession();
        	SqlSession sqlSession3 = SqlSessionFactorySingleton.getinstance().openSession();
        	SqlSession sqlSession4 = SqlSessionFactorySingleton.getinstance().openSession();
    
        	UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
        	UserMapper userMapper2 = sqlSession1.getMapper(UserMapper.class);
        	UserMapper userMapper3 = sqlSession1.getMapper(UserMapper.class);
        	UserMapper userMapper4 = sqlSession1.getMapper(UserMapper.class);
    
        	
        	//第一次查询
        	User user = userMapper1.finduserbyid(2);
        	System.out.println(user);
        	
        	sqlSession1.close();
        	
        	//第一次查询之后更改
        	user.setName("Pack");
        	userMapper2.updateuser(user);
        	sqlSession3.commit();;
        	
        	//第二次查询
        	User user2 = userMapper2.finduserbyid(2);
        	System.out.println(user2);
        	
        	//sqlSession2.close();
        }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值