java持久层框架优秀的MyBatis

mybatis笔记

框架阶段大量用到了xml 反射 动态代理的相关知识需回顾

#####.mybatis简介

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。 

#####.mybatis概念

mybatis是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,
而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。
mybatis通过 xml 或注解的方式将要执行的各种statement配置起来,并通过java对象和statement 中
sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并
返回。
采用 ORM 思想解决了实体和数据库映射的问题,对 jdbc进行了封装,屏蔽了 jdbc api 底层访问细节,使我
们不用与 jdbc api 打交道,就可以完成对数据库的持久化操作。

MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。 MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及对结果集的检索。 MyBatis 可以使用简单的XML 或注解用于配置和原始映射,将接口和 Java 的 POJO( Plain Old Java Objects,普通的Java 对象)映射成数据库中的记录.

#####.相关名词解释:

1.pojo:

		POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,
		POJO实质上可以理解为简单的实体类,顾名思义POJO类的作用是方便程序员使用数据库中的数据表,对于广大的程序员,可以很方便的将POJO类当做对象来进行使用,当然也是可以方便的调用其get,set方法。POJO类也给我们在struts框架中的配置带来了很大的方便。

2.ORM思想:

		对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换 。从效果上说,它其实是创建了一个可在编程语言里使用的--“虚拟对象数据库”。就是把数据库表和实体类及实体类的属性对应起来,让我们可以操作实体类就实现操作数据库表。

#####.mybatis开发模式三种

1. 接口+xml方法:只写接口,但接口方法的命名要与xml的id名一致。
	特点:  处理业务和代码可复用性较好但存在繁琐的xml
2. 注解方式:在接口方法上面写SQL语句
	特点:  简洁但处理复杂业务则代码可读性不好
3. 接口+实现类的方式
	特点:  处理缓存和处理事务方便但添加了多余的代码
4. 总结
	1. 对于简单语句来说,注解使代码显得更加简洁,然而 Java 注解对于稍微复杂的语句就会力不从心并且会显得更加混乱。因此,如果你需要做很复杂的事情,那么最好使用 XML 来映射语句。
mybatis接口+xml开发模式介绍
1. 搭建Mybatis开发环境
	1. 创建maven工程
		1. 在 pom.xml 文件中添加 Mybatis3.4.5 的坐标
			<dependencies>
				<dependency>
					<groupId>org.mybatis</groupId>
					<artifactId>mybatis</artifactId>
					<version>3.4.5</version>
				</dependency>
				....
			</dependencies>


	2. 编写实体类
		1. 例如编写用户的实体类 实现Serializable接口	Serializable:序列化
			1. 解释实现Serializable接口的原因
				* 首先,序列化的目的有两个,第一个是便于存储,第二个是便于传输。让实体类实现Serializable接口时,其实是在告诉JVM此类可被序列化,可被默认的序列化机制序列化。



	3. 编写持久层(方法)接口UserDao(**就相当于UserMapper**)
		1. 在myabtis中的mapper接口相当于dao层,调用mapper接口的方法即可实现对数据库的增删改查操作
		2. 提供方法
			1. public abstract List<User> findAll();	//基于xml

			2. @Select("select * from user")
				public abstract List<User> findAll();	//基于注解



	4. 编写持久层接口的映射文件UserDao.xml(UserMapper.xml)
		1. 映射配置文件(UserMapper.xml/UserDao.xml)位置必须和持久层接口(UserMapper.java/UserDao.java)的文件名一致而且包结构相同(cn.itcast.dao)
			1. 在一个 XML 映射文件中,定义多少个映射语句都是可以的
		2. 映射配置文件的mapper标签 namespace 属性的取值必须是持久层(dao)接口的全限定类名(cn.itcast.dao.UserDao)除非在主配置文件中起了别名
			1. 这样当我们调用UserMapper.java接口中的方法时,通过namespace=cn.itcast.dao.UserDao将接口和配置文件联系在了一起。
			2. 在命名空间(namespace)“cn.itcast.dao.UserDao”中定义了一个名为“findAll”的映射语句,这样它就允许你使用指定的完全限定名“cn.itcast.dao.UserDao.findAll”来调用映射语句
			3. 这样做是有原因的。这个命名可以直接映射到在命名空间中同名的 Mapper 类,并将已映射的 select 语句中的名字、参数和返回类型匹配成方法。这样你就可以像上面那样很容易地调用这个对应 Mapper 接口的方法。

		3. 映射配置文件的mapper标签下的增删改查标签对应持久层接口中的方法
			1. 在增删改查标签中的id属性必须和接口中的方法名相同,id属性值必须是唯一的,不能够重复使用。
				*. UserMapper(UserDao)接口中的方法名和 UserMapper.xml 文件中定义的 id 一致

			2. parameterType属性指明查询时使用的参数类型
				*. UserMapper接口中方法输入参数类型要和 UserMapper.xml 中定义的 parameterType 一致 

			3. resultType属性指明查询返回的结果集类型
				*. UserMapper接口返回数据类型要和 UserMapper.xml 中定义的 resultType 一致 

			4. #{} 和${}区别
				*. 在mybatis中的$与#都是在sql中动态的传入参数。#{}是预编译处理,${}是字符串替换。mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;mybatis在处理${}时,就是把${}替换成变量的值。使用#{}可以有效的防止SQL注入,提高系统安全性。 
					1. #是将传入的值当做字符串的形式 当使用#时变量是占位符,就是一般我们使用java jdbc的PrepareStatement时的占位符?,所以可以很大程度上防止sql注入
						1. #{}中的内容,为占位符,当参数为某个JavaBean时,表示放置该Bean对象的属性值
					2. $是将传入的数据直接显示生成sql语句 ${}仅仅为一个纯碎的 string 替换,一般会有sql注入问题
				
					*  #{} 表示一个占位符号通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,#{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。如果 parameterType 传输单个简单类型值,#{}括号中可以是 value 或其它名称。
					*  ${} 表示拼接 sql串通过${}可以将 parameterType 传入的内容拼接在 sql中且不进行 jdbc 类型转换, ${}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value。

			5. insert 映射插入语句
				1. 在映射配置文件中添加insert标签,标签上以parameterType属性设置参数类型。在标签体内编写insert语句,使用参数的时候,如果从JavaBean中获取值,使用#{ 属性名} 格式获取
				2. 在sqlSession获取dao代理对象时,默认执行sql时是不自动提交事务的。所以如果涉及到增删改操作,不要忘记提交事务。调用SqlSession的commit方法即可。
				3. 在插入数据之后如果需要获取插入的这条记录的id值,可以使用selectKey标签。标签体内可以执行一条sql语句。	select last_insert_id();  获取最后一条记录插入时的主键值。这个值查询出来之后可以设置到参数的user对象的id上
					*.keyProperty="userId"  -- 在user对象中的属性名称
					*.keyColumn="id"        -- 在数据库表中的字段名称
					*.order="AFTER"         --当前指定的statement是在语句之前执行还是之后执行。 
			6. delete 映射删除语句
				1. 删除时传入的参数是int类型的id。如果参数是基本数据类型并且参数的个数只有一个,在sql语句中获取参数值的时候,#{}中的key可以任意编写。
				2. 如果dao中参数是多个数据的列表,在sql语句中获取参数值的时候,首先parameterType可以不指定,#{}中使用arg0,arg1...的方式获取持久层接口对应方法所需传递的参数。0、1...代表的是dao中的参数的索引。
			7. select 映射查询语句
				1. 当使用模糊查询如果传参时获取参数使用#{}的方式,必须在调用时真正传递参数的时候在参数上添加%或_。推荐使用 
				2. 如果传参时获取参数使用'%${value}%'方式,无需在传递参数时指定%或_。但是{}中只能写value,所以不推荐这种写法


	5. 编写mybatis总配置文件Configuration.xml(SqlMapConfig.xml)
		1.  要注意 XML 头部的声明,用来验证 XML 文档正确性。environment 元素体中包含了事务管理和连接池的配置。mappers 元素则是包含一组 mapper 映射器(这些 mapper 的 XML 文件包含了 SQL 代码和映射定义信息).XML 配置文件(configuration XML)中包含了对 MyBatis 系统的核心设置,包含获取数据库连接实例的数据源(DataSource)和决定事务作用域和控制方式的事务管理器(TransactionManager)
		2.   "configuration"的内容必须匹配"
				(properties,
				settings,
				typeAliases,
				typeHandlers,
				objectFactory,
				objectWrapperFactory,
				reflectorFactory,
				plugins,
				environments,
				databaseIdProvider,
				mappers)"。 
		3. xml文档高层级结构如下
			* configuration配置
				* properties 属性
					--property
				* settings 设置
					--setting
				* typeAliases 类型别名
					--typeAliase
					--package
				* typeHandlers类型处理器
				* objectFactory对象工厂
				* plugins插件
				* environments 环境
					-- environment 环境变量
						-- transactionManager 事务管理器
						-- dataSource数据源

				* mappers (映射器)
					--mapper
					--package

		4. 示例
			* <?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>
						<!-- 配置 mybatis 的环境 -->
				  <environments default="development">
				    <environment id="development">
						<!-- 配置事务的类型 -->
				      <transactionManager type="JDBC"/>
						 <!-- mybatis提供了3种数据源类型,分别是:POOLED,UNPOOLED,JNDI -->
			            <!-- POOLED 表示支持JDBC数据源连接池 -->
			            <!-- UNPOOLED 表示不支持数据源连接池 -->
			            <!-- JNDI 表示支持外部数据源连接池 -->
						<!-- 配置连接数据库的信息:用的是数据源(连接池) -->
				      <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>
						<!-- 告知 mybatis 映射配置的位置 -->
						<!-- 配置 dao 接口的位置,它有两种方式
								第一种:使用 mapper 标签配置 class 属性
								第二种:使用 package 标签,直接指定 dao 接口所在的包-->
				  <mappers>
				    <mapper resource=cn/itcast/dao/UserDao.xml"/>
				  </mappers>
				</configuration> 


	6. 编写测试类 测试 mybatis 的环境
		*  每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。既然有了 SqlSessionFactory ,顾名思义,我们就可以从中获得 SqlSession 的实例了。SqlSession 完全包含了面向数据库执行 SQL 命令所需的所有方法.从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。但是也可以使用任意的输入流(InputStream)实例,包括字符串形式的文件路径或者 file:// 的 URL 形式的文件路径来配置。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,可使从 classpath 或其他位置加载资源文件更加容易。
			public class MybatisTest {
				private InputStream is;
			    private SqlSession sqlSession;
			    private UserDao userDao;

				/**
			     * 在所有测试方法执行之前执行的初始化方法
			     * 准备材料的过程
			     */
			    @Before
			    public void init() throws Exception {
			        //读取配置文件 获取连接数据库的信息
					//is = Resources.getResourceAsStream("Configuration.xml");
			        is = MybatisTest.class.getClassLoader().getResourceAsStream("Configuration.xml");
			        //创建 SqlSessionFactory 的构建者对象
			        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
					//使用构建者创建工厂对象 SqlSessionFactory
			        SqlSessionFactory factory = builder.build(is);
			        //使用 SqlSessionFactory 生产 SqlSession 对象
			        sqlSession = factory.openSession();
			        //使用 SqlSession 创建 dao 接口的代理对象
			        userDao = sqlSession.getMapper(UserDao.class);
			        //使用代理对象执行方法
			    }

			   /**
			     * 在所有测试方法执行之后执行的善后工作
			     */
			    @After
			    public void destroy() throws Exception {
			        //提交事务
			        sqlSession.commit();
			        //释放资源
			        sqlSession.close();
			        is.close();
			    }

				//使用代理对象执行方法
			}


3. 总结
	1. 基于代理dao实现CRUD操作
		1. 持久层接口和持久层接口的映射配置必须在相同的包下
		2. 持久层映射配置中 mapper 标签的 namespace 属性取值必须是持久层接口的全限定类名
		3. SQL 语句的配置标签<select>,<insert>,<delete>,<update>的 id 属性必须和持久层接口的方法名相同。
基于注解的 mybatis
    1. 在mybatis总配置文件Configuration.xml中修改映射配置(两种方式)
	    1.    
	     	<mappers>
	        	<mapper class="cn.itcast.dao.UserDao"/>
	    	</mappers>
		2. 
			<mappers>
		        <package name="cn.itcast.dao"/>
		   </mappers>

	2. 移除 xml 的映射配置(IUserDao.xml)。
	
    3. 在持久层接口中添加注解
	    1. 在定义的方法上配置上应有的注解,注解中含有sql语句 实现对数据的增删改查,将sql语句直接写在注解的括号中
		    @Select("select * from user")
			public abstract List<User> findAll();

	4. 如果结果集和最终的实体类属性没有直接对应关系,映射关系的配置使用 @Results注解。
		1. 在Results注解中
		2. id属性:它就是来给该Results注解提供的一个唯一标识,以供其他方法使用 
		3. 使用 @Result注解配置单个字段的对应关系。
			1. id属性用于指定当前是否是主键(主键则设置为true)。
			2. 非主键不需要id属性只有column(字段名)和property(属性名)
		4. 需要在其他方法上使用时
			1. 在该方法上加上@ResultMap()注解
			2. @ResultMap()注解中的value属性指定一个@Result注解id属性就代表引用了这个Results注解中配置的映射关系。
			3. 标准写法: @ResultMap(value={"userMap"})
				@Select("select * from user  where id=#{id} ")
			    @ResultMap("userMap")
			    User findById(Integer userId);

	5. 复杂关系映射的注解说明
		1. @Results  注解
			代替的是标签<resultMap>
			该注解中可以使用单个@Result 注解,也可以使用@Result 集合
			@Results({@Result(),@Result()})或@Results(@Result())

		2. @Resutl 注解
			代替了 <id> 标签和<result> 标签
			@Result  中  属性介绍:
				id 是否是主键字段
				column 数据库的列名
				property 需要装配的属性名
				one 需要使用的@One 注解(@Result(one=@One)()))
				many 需要使用的@Many 注解(@Result(many=@many)()))

		@One  注解(一对一)(多对一 mybatis中称之为一对一的映射)
			代替了<assocation> 标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
		@One  注解属性介绍:
			select 指定用来多表查询的sqlmapper(要找到能实现功能的方法 全限定类名+方法名)
					select:指定的是一个statement的id,用于查找另一个dao中的方法查询实体类作为值设置到当前属性上
			fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。
					fetchType:用于指定加载的方式,可以是懒加载或者直接加载。一般配置为直接加载
		使用格式:
			@Result(column=" ",property="",one=@One(select=""))
			例1. 
				查询所有账户,并且获取每个账户所属的用户信息
					@Select("select * from account")
				    @Results(id="accountMap",value = {
				            @Result(id=true,column = "id",property = "id"),
				            @Result(column = "uid",property = "uid"),
				            @Result(column = "money",property = "money"),
				            @Result(property = "user",column = "uid",one=@One(select="cn.itcast.dao.UserDao.findById",fetchType= FetchType.EAGER))
				    })
				    List<Account> findAll();

		@Many  注解(一对多)
			代替了<Collection> 标签, 是是多表查询的关键,在注解中用来指定子查询返回对象集合。
			select 指定用来多表查询的sqlmapper(要找到能实现功能的方法全限定类名+方法名)
					select:指定的是一个statement的id,用于查找另一个dao中的方法查询实体类作为值设置到当前属性上
			fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。
					fetchType:用于指定加载的方式,可以是懒加载或者直接加载。一般配置为直接加载
		注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType
		(一般为 ArrayList)但是注解中可以不定义;
		使用格式:
			@Result(property="",column="",many=@Many(select=""))
			例2. 
				查询所有用户以及用户下的账户列表
				@Select("select * from user")
			    @Results(id="userMap",value={
			            @Result(id=true,column = "id",property = "userId"),
			            @Result(column = "username",property = "userName"),
			            @Result(column = "address",property = "userAddress"),
			            @Result(column = "sex",property = "userSex"),
			            @Result(column = "birthday",property = "userBirthday"),
			            @Result(property = "accounts",column = "id",
			                    many = @Many(select = "com.itheima.dao.IAccountDao.findAccountByUid",
			                                fetchType = FetchType.LAZY))
			    })
			    List<User> findAll();
		
	6. mybatis 基于注解的二级缓存
		1. 在SqlMapConfig.xml中开启二级缓存支持
			<!-- 配置二级缓存 -->
			<settings>
				<!-- 开启二级缓存的支持 -->
				<setting name="cacheEnabled" value="true"/>
			</settings> 
		2.  在持久层接口中使用注解配置二级缓存
			@CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存
			public interface UserDao {}  
基于代理dao实现CRUD操作细节
	1. 根据id查询一个或者删除一个时时
		<select id="findById" resultType="com.itheima.domain.User" parameterType="int">
			select * from user where id = #{uid}
		</select>
		<delete id="deleteUser" parameterType="java.lang.Integer">
			delete from user where id = #{uid}
		</delete>
		1.  	#{} 中内容的写法:由于数据类型是基本类型,所以此处可以随意写。

	2. 保存操作时 
		<insert id="saveUser" parameterType="com.itheima.domain.User">
			insert into user(username,birthday,sex,address)
			values(#{username},#{birthday},#{sex},#{address})
		</insert>
		1. 	#{}中内容的写法:由于我们保存方法的参数是 一个 User 对象,此处要写 User 对象中的属性名称。它用的是 ognl 表达式。
			补充:
				ognl 表达式:它是 apache 提供的一种表达式语言
				全称是:Object Graphic Navigation Language 对象图导航语言它是按照一定的语法格式来获取数据的。语法格式就是使用 #{对象.对象}的方式 
		2. 获取什么属性就直接打.后面跟属性名获取即可。相当于调用了对应对象的getter方法。如果有多层对象嵌套。可以继续打.递归获取。#{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用getUsername()方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,所以可以省略 user.而直接写 username。	

	3. 模糊查询操作时
		1. 配置文件中没有加入%来作为模糊查询的条件,所以在传入字符串实参时,就需要给定模糊查询的标识%。配置文件中的#{username}也只是一个占位符,所以 SQL 语句显示为“?”。 
		<select id="findByName" resultType="com.itheima.domain.User" parameterType="String">
			select * from user where username like #{username}
		</select>
		2. 若将原来的#{}占位符,改成了${value}。注意如果用模糊查询的这种写法,那么${value}的写法就是固定的,不能写成其它名字。
		<select id="findByName" parameterType="string" resultType="com.itheima.domain.User">
			select * from user where username like '%${value}%'
		</select>

	4. #{} 与${} 的区别
		1. #{} 表示一个占位符号通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,#{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类型值,#{}括号中可以是 value 或其它名称。
		2. ${} 表示拼接 sql  串通过${}可以将 parameterType 传入的内容拼接在 sql中且不进行 jdbc 类型转换, ${}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value。
parameterType参数配置
 1. SQL语句传参,使用标签的 parameterType 属性来设定。该属性的取值可以是基本类型,引用类型(例如:String 类型),还可以是实体类类型(POJO 类)。同时也可以使用实体类的包装类.mybaits 在加载时已经把常用的数据类型(例如基本类型和String)注册了别名,从而我们在使用时可以不写包名(也可以使用包名.类名的方式)

 2. 开发中通过pojo传递查询条件,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象(查询条件对象)传递输入参数。
	 1. 把实体类封装进一个查询条件对象QueryVo,该实体类便成为一个成员属性提供getXxx/setXxx方法
	 2. 当传递参数为一个或多个时parameterType可以指定为QueryVo对象(查询条件对象),此时sql中的参数就要使用该对象中的属性(实体类).属性
		 1. 持久层接口中提供方法 参数传递查询条件对象
		public abstract List<Student> findByageAndSex(QueryVo queryVo);
		 2. 持久层接口的映射配置文件中 
		 <select id="findByageAndSex" parameterType="QueryVo" resultType="student">
	        select * from student WHERE age > #{student.age} and sex = #{student.sex};
	    </select>
Mybatis输出结果封装
 1. resultType 属性可以指定结果集的类型(pojo、简单类型、hashmap),将SQL查询结果映射为Java对象.它支持基本类型和实体类类型。它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。没有注册过的必须使用全限定类名
	 注意: 
		1. sql查询的列名要和resultType指定pojo的属性相同,指定相同,属性方可映射成功。如果sql查询的列名要和resultType指定实体类(pojo)的属性全部不相同,list中是无法创建实体类(pojo)对象的。有几个属性对应相同,则能给对应相同的属性赋值。 
		2. 如果SQL查询列名和最终要映射的pojo的属性名不一致,
			1. 可以起别名的形式,若查询很多时则不宜使用	优点:效率高
				<select id="findAll" resultType="com.itheima.domain.User">
					select id as userId,username as userName,birthday as userBirthday,
					sex as userSex,address as userAddress from user
				</select> 
			2. 使用resultMap将列名和实体类(pojo)的属性名做一个映射关系(列名和属性名映射配置)从而实现封装。在 select 标签中使用resultMap 属性指定引用即可。同时 resultMap 可以实现将查询结果映射为复杂类型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。		效率较低
			1. type 属性:指定实体类的全限定类名
			2. id 属性:给定一个唯一标识,是给查询 select 标签引用用的。
			<resultMap type="com.itcast.dao.User" id="userMap">
		        <id column="id" property="id" />
		        <result column="userName" property="userName" />
		        <result column="passWord" property="passWord" />
		    </resultMap>
				id 标签:用于指定主键字段
				result 标签:用于指定非主键字段
				column 属性:用于指定数据库列名
				property 属性:用于指定实体类属性名称
				column的值对应着property的值,即数据库字段(column)对应着pojo对象的属性(property)。
SqlMapConfig.xml(Configuration.xml)的配置
1. properties 标签配置
	1. 在使用 properties 标签配置时,我们可以采用两种方式指定属性配置。
		1. 定义在内部:在SqlMapConfig.xml中对数据库连接参数硬编码。 在标签内部配置连接数据库的信息
		2. 将数据库连接参数单独配置在jdbcConfig.properties中,放在类路径下。通过属性引用外部配置文件信息,这样只需要在SqlMapConfig.xml中加载jdbcConfig.properties的属性值。这样在SqlMapConfig.xml中就不需要对数据库连接参数硬编码。
			优点: 方便对参数进行统一管理,其它xml可以引用该jdbcConfig.properties。
			1. <properties resource="jdbcConfig.properties"></properties>
				* resource 属性:用于指定 properties 配置文件的位置,要求配置文件必须在类路径下
			2. 在SqlMapConfig.xml dataSource标签下的property标签中数据库连接参数只需要 
				<property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>这样引入即可

	2. 注意: MyBatis 将按照下面的顺序来加载属性:
		首先在properties标签中指定的属性文件首先被读取。 然后会读取properties元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。 最后读取parameterType传递的属性,它会覆盖已读取的同名属性。

	3. 常用做法:不要在properties元素体内添加任何属性值,只将属性值定义在外部properties文件中。
		在properties文件中定义属性名要有一定的特殊性,如:XXXXX.XXXXX.XXXX的形式,就像jdbc.driver。这样可以防止和parameterType传递的属性名冲突,从而被覆盖掉。







2. typeAliases 标签配置别名 只能配置domain中类的别名
	1. typeAliases可以用来自定义别名。在mapper.xml(UserDao.xml)中,定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心.而statement(执行sql的对象)需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。如果在指定类型时如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。
	2.	<typeAlias type="cn.itcast.domain.User" alias="user"/>	 type属性指定的是实体类的全限定类名.alias属性指定别名 但当有多个实体类时不宜使用
	3.	<package name="cn.itcast.domain"/>	使用这种方式以name属性指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,同时不再区分大小写
				<typeAliases>
					<!-- 单个别名定义 -->
					<typeAlias alias="user" type="cn.itcast.domain.User"/>
					<!-- 批量别名定义,扫描整个包下的类,别名为类名(不区分大小写)-->
					<package name="cn.itcast.domain"/>
					<package name="其它包"/>
				</typeAliases> 


3. mappers(映射器)
	1. 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件(持久层接口的映射文件)
		1. <mapper resource=" " />	使用相对于类路径的资源
			* <mapper resource="cn/itcast/dao/UserDao.xml"/>
		2. <mapper class=" " />		基于注解开发时使用这种方式
			* <mapper class="cn.itcast.dao.UserDao"/> 
		3. <package name=""/>	注册指定包下的所有mapper接口(用于指定dao接口所在的包),当指定以后就不需要在写mapper以及resource或者class了
			* <package name="cn.itcast.dao"/> 
动态sql
1. mybatis动态生成sql
	1. 逻辑标签
		1. if标签
			1. <if>标签的 test 属性中写的是对象的属性名,如果是包装类的对象要使用 OGNL 表达式的写法。
				test指定条件,boolean值
				test中可以直接使用OGNL表达式
		2. foreach标签 用于遍历集合
			<foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
				collection:要遍历的集合
				open:将要拼接的sql的开始的字符串(代表语句的开始部分)
				close:将要拼接的sql的结束的字符串(代表结束部分)
				item : 代表遍历集合的每个元素,生成的变量名
				separator:分隔符,在此处in语句中使用,分割条件列表
		3. where标签 包裹在if标签之外即可
			1. 为了简化where 1=1 的条件拼装,可以采用<where>标签来简化开发。
		4. sql标签
			1. 将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的
				1. 定义代码片段
					<!-- 抽取重复的语句代码片段 -->
					<sql id="defaultSql">
						select * from user
					</sql> 
				2. 引用代码片段
					<!-- 配置查询所有操作 -->
					<select id="findAll" resultType="user">
						<include refid="defaultSql"></include>
					</select> 
Mybatis 多表查询
mybatis实现多表操作时,我们使用了resultMap来实现一对一,一对多,多对多关系的操作。主要是通过 association、collection 实现一对一 及一对多映射。

1. 一对一查询(多对一)
	1. 从表实体应该包含一个主表实体的对象引用	
		1. 查询所有账户信息,关联查询下单用户信息。
		2. 在 Account 类中加入 User 类的对象作为 Account 类的一个属性,提供getXxx/setXxx。
			1. 在AccountDao.xml中配置(结果集字段和JavaBean的对应关系)
				1. 使用<resultMap></resultMap>中建立对应关系
					1. id: 唯一标识 方便引用
					2. type: 结果集类型
							1. id: 定义唯一主键 	
								1. property: 属性
								2. column: 字段名
							2. 用<result></result>定义非主键
								1. property: 属性
								2. column: 字段名
				2. 在<resultMap></resultMap>通过以上配置就能完成account数据封装完成还需继续封装user
				3. 在<association></association>建立一对一的关系映射 配置封装user的内容 用于指定从表方的引用实体属性的
					1. property:实体属性名
					2. column: 通过哪个字段名来获取
						1. 使用<result></result>标签
							1. id: 定义唯一主键 	
								1. property: 属性
								2. column: 字段名
							2. 用<result></result>定义为主键
								1. property: 属性
								2. column: 字段名

2. 一对多查询
	1. 一对多关系映射:主表实体应该包含从表实体的集合引用
		1. 查询所有用户信息及用户关联的账户信息。
		2. 在User类中加入Account类的集合属性,提供getXxx/setXxx.
			1. 在UserDao.xml中配置
				1. 使用<resultMap></resultMap>中建立对应关系
					1. id: 唯一标识 方便引用
					2. type: 结果集类型
							1. id: 定义唯一主键 	
								1. property: 属性
								2. column: 字段名
							2. 用<result></result>定义非主键
								1. property: 属性
								2. column: 字段名
				2. 在<collection></collection>建立一对多中集合属性的对应关系 配置user对象中accounts集合的映射
					1. property: 集合名称	关联查询的结果集存储在 User 对象的上哪个属性。
					2. ofType: 用于指定集合中元素的类型(泛型)	指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名。
						1. 使用<result></result>标签
							1. id: 定义唯一主键 	
								1. property: 属性
								2. column: 字段名
							2. 用<result></result>定义为主键
								1. property: 属性
								2. column: 字段名  

3. 多对多查询
	1. 多对多关系其实可以看成是两个一对多关系
		1. Role到User多对多	
			1. 一个角色可以赋予多个用户
			2. 一个用户可以具有多个角色
		2. 所以User 与 Role 的多对多关系,可以被拆解成两个一对多关系来实现。
			1. 实现查询所有角色并且加载它所分配的用户信息。
			2. 实现查询所有用户信息并关联查询出每个用户的角色列表。

#####Mybatis延迟加载
本质上,延迟加载就是把原来需要多表级联查询的语句拆分成了多个单表查询语句,然后组合结果集封装的效果。
一对一(多对一在mybatis中也称之为一对一) 时通常选择立即加载,一对多时通常选择延迟加载

1. 概念: MyBatis中的延迟加载,也称为懒加载,是指在进行关联查询时,按照设置延迟规则推迟对关联对象的select查询。延迟加载可以有效的减少数据库压力。

2. 注意: MyBatis的延迟加载只是对关联对象的查询有延迟设置,对于主加载对象都是直接执行查询语句的。

3. 延迟加载的条件:
	resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。

4. 延迟加载的好处:
	先从单表查询、需要时再从关联表去关联查询,大大提高 数据库性能,因为查询单表要比关联查询多张表速度要快。

5. 延迟加载的实例:
	如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。

6. 开启延迟加载
	Mybatis的延迟加载功能默认是关闭的,需要在SqlMapConfig.xml文件中通过setting标签配置来开启延迟加载功能

7. 开启延迟加载的属性:
	lazyLoadingEnabled:延迟加载的全局开关(全局性设置懒加载)。如果设为‘false’,则所有相关联的都会被初始化加载。默认为false
	aggressiveLazyLoading:当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。默认为true
8. 延迟加载的resultMap
	在resultMap中使用association或者collection,即可使用延迟加载。
	延迟加载需要两个statement语句来完成
	在resultMap中使用association或者collection来配置两个statement直接的管理

######使用association实现延迟加载(一对一)
1.需求:查询账户信息同时查询用户信息。(一对一)
1. 在中建立对应关系
2. 在建立一对一的关系映射
1. select: 要调用的 select 映射的id(要延迟加载的statement的id)
2. column: 要传递给 select 映射的参数(关联两张表的那个列的列名)
3. 需要在 Mybatis 的配置文件 SqlMapConfig.xml 文件中添加延迟加载的配置。




######使用collection实现延迟加载(一对多)
1. 需求:完成加载用户对象时,查询该用户所拥有的账户信息
1. 在用户持久层中编写映射配置
1. 在中建立对应关系
2. 在是用于建立一对多中集合属性的对应关系,主要用于加载关联的集合对象
1. select:是用于指定查询账户的唯一标识
2. column:是用于指定使用哪个字段的值作为条件查询( select属性的sql语句的参数来源)
3. ofType:用于指定集合元素的数据类型

#####Mybatis缓存
Mybatis提供缓存,用于减轻数据压力,提高数据库性能。Mybatis的缓存分为一级缓存和二级缓存,默认情况下是没有开启缓存的,除了局部的 session 缓存.

1. 一级缓存:
	1. 一级缓存是SqlSession级别的缓存,存在于SqlSession对象中,一级缓存存储的是实体类对象
		1. 当一次执行查询的时候,首先会去查询一级缓存,如果一级缓存中没有数据,然后才回去查询数据库,数据库返回后会将返回的数据保存到一级缓存之中。
	 	2. 第二次再去查询相同的数据时,就会直接从一级缓存中取数据,不再需要去查询数据库。
	 	3. 如果在两次查询之间执行了SqlSession的commit(),close(),clearCache()方法时或者执行插入、更新、删除,则会清空一级缓存,这样是为了防止读到脏数据。

2. 二级缓存:
	**二级缓存中实际存储的是数据而不是实体类对象。所以即使使用了缓存,获取到的数据是相同的,也没有多次查询数据库,但是实体类不是同一个。**
	1. 二级缓存跟随SqlSessionFactory存在,同一个工厂对象创建的所有SqlSession共享这一块二级缓存空间
	注意: 二级缓存需要查询结果映射的pojo对象实现java.io.Serializable接口实现序列化和反序列化操作,这种就可以使用序列化方式来保存对象。注意如果存在父类、成员pojo都需要实现序列化接口。
		1. 二级缓存是Mapper级别的缓存。
		2. 二级缓存的结构也是一个HashMap。
		3. 不同的SqlSession对象去操作同一个mapper中的SQL语句,多个SqlSession共用二级缓存。
		4. 二级缓存的作用域是mapper的同一个namespace,如果两个mapper文件的namespace相同,则这两个共用二级缓存。
		5. Mybatis的二级缓存需要配置开启 
			1. 当SqlSession1一次执行查询的时候,首先会去查询二级缓存,如果二级缓存中没有数据,然后才回去查询数据库,数据库返回后会将返回的数据保存到二级缓存之中。
			2. 第二次SqlSession2再去查询相同的数据时,就会直接从二级缓存中取数据,不再需要去查询数据库。
			3. 如果在两次查询之间执行了SqlSession3的commit操作(执行插入、更新、删除),则会清空二级缓存,这样是为了防止读到脏数据。 
			
	2. 在SqlMapConfig.xml设置二级缓存的总开关
		<settings>
	        <!--开启二级缓存-->
	        <setting name="cacheEnabled" value="true" />
	    </settings>

	3. 在具体的mapper.xml中开启二级缓存。
		1. 在mapper标签内部,编写cache标签,代表当前dao支持缓存	
		<cache>标签表示当前这个 mapper 映射将使用二级缓存,区分的标准就看 mapper 的 namespace 值。
			<?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="cn.itcast.dao.UserDao">
				<!-- 开启二级缓存的支持 -->
				<cache></cache>
			</mapper>

	4. 配置statement上面的useCache属性
		<!-- 根据 id 查询 -->
		<select id="findById" resultType="user" parameterType="int" useCache="true">
			select * from user where id = #{uid}
		</select>
		将 UserDao.xml 映射文件中的<select>标签中设置 useCache=”true”代表当前这个 statement 要使用
		二级缓存,表示当前操作的结果存入二级缓存,如果不使用二级缓存可以设置为 false,实体类必须实现序列化接口。
		注意:针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。  


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值