Mybatis第一天

什么是数据持久化

数据持久化是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称。例如:文件的存储,数据的读取等都是数据持久化的操作。狭义的理解: “持久化”仅仅指把域对象永久保存到数据库中;广义的理解,“持久化”包括增删改查等数据库相关的各种操作。

Mybatis框架介绍

Mybatis是一个开源的半ORM1框架,因为它在查询对象和关联对象集合时需要手动写sql语句。

为什么使用Mybatis?

  1. Mybatis消除了大量的JDBC冗余代码
  2. Mybatis有低的学习曲线
  3. Mybatis能很好地与传统数据库协同工作
  4. Mybatis可以接受SQL语句
  5. Mybatis提供了与Spring框架的集成支持
  6. Mybatis提供了与第三方缓存类库的集成支持
  7. Mybatis引入了更好的性能

搭建Mybatis环境

  1. 下载jar包
  2. 创建Mybatis核心配置文件
    mybatis的配置文件一般来说名字是固定的,就叫 mybatis-config.xml ,其中包括数据库连接信息,类型别名,映射文件路径等等;直接创建在src目录下。
    案例:
<?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>
	<typeAliases>
 		<typeAlias alias="Student" type="com.test.pojo.Student"
/>
	</typeAliases>
	<settings>
		<setting name="logImpl" value="LOG4J"></setting>
	</settings>
  	<environments default="development">
 		<environment id="development">
  			<transactionManager type="JDBC" />
   			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver" />
		 	<property name="url" value="jdbc:mysql://localhost:3306/test" />
  			</dataSource>
 		</environment>
	</environments>
	<mappers>
		<mapper resource="com/test/pojo/StudentMapper.xml" />
	</mappers>
</configuration>

mybatis核心配置文件的节点元素介绍:

  • configuration:配置文件的根节点元素
  • properties:通过resources属性从外部指定包括数据源等配置文件,使用${属性名}引用。
  • environments:是配置mybatis当前工作的数据库环境的地方
  • dataSource 表示的是数据源;至少会包括该连接数据库的四种信息.dataSource的类型type属性可以配置成其内置类型之一,如UNPOOLED,POOLED,JNDI。
    如果将类型设置成UNPOOLED,MyBatis会为每一个数据库操作创建一个新的连接,使用完了并关闭它,该方式适用于只有小规模数量并发用户的简单应用程序上。
    如果将属性设置成POOLED,MyBatis会创建一个数据库连接池,连接池中的一个连接将会被用作数据库操作(分配,管理,释放)。一旦数据库操作完成,MyBatis会将此连接返回给连接池。
    如果将类型设置成JNDI(Java Naming and Directory Interface , Java命名和目录接口, 是SUN公司提供的一种标准的Java命名系统接口),MyBatis从在应用服务器向配置好的JNDI数据源dataSource获取数据库连接。在生产环境中,优先考虑这种方式。
  • transactionManager元素JDBC事务管理器的使用,是在 JDBC程序 负责管理数据库连接的生命周期(提交、回退等等)的时候。如果将TransactionManager 属性设置成JDBC,MyBatis内部将使用JdbcTransactionFactory类创建TransactionManager。例如,部署到ApacheTomcat的应用程序,需要应用程序自己管理事务。
    MANAGED 事务管理器的使用,是在 应用服务器 负责管理数据库连接生命周期的时候。如果TransactionManager属性设置成MANAGED时,MyBatis内部使用ManagedTransactionFactory类创建事务管理器TransactionManager。例如,当一个Java EE的应用程序部署在类似JBoss,WebLogic,GlassFish等应用服务器上时,它们会使用EJB进行应用服务器的事务管理能力。在这些管理环境中,你可以使用MANAGED事务管理器。
  • typeAliases: 为pojo指定别名当然也可以可以不用为每一个JavaBean单独定义别名,你可以为配置出需要取别名的类的所在的包(package),MyBatis会自动扫描包内定义的类,然后分别为每个类注册一个小写字母开头的简单类名形式的别名。
  • typeHandlers元素,对于mapper中传参方式#{属性名},基本数据类型和String,Date等一般mybatis使用自带的typeHandler,对于自定义类型,需要用户自定义TypeHandler进行处理。继承抽象类BaseTypeHandler,然后再mybatis-config.xml中注册
  • settings元素
<settings>
    <!-- 这个配置使全局的映射器启用或禁用缓存 -->
    <setting name="cacheEnabled" value="true" />
    <!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载 -->
    <setting name="lazyLoadingEnabled" value="true" />
    <!-- 允许或不允许多种结果集从一个单独的语句中返回(需要适合的驱动) -->
    <setting name="multipleResultSetsEnabled" value="true" />
    <!-- 使用列标签代替列名。不同的驱动在这方便表现不同。参考驱动文档或充分测试两 种方法来决定所使用的驱动 -->
    <setting name="useColumnLabel" value="true" />
    <!-- 允许JDBC支持生成的键。需要适合的驱动。 -->
    <setting name="useGeneratedKeys" value="false" />
    <!-- 指定MyBatis如何自动映射列到字段/属性。PARTIAL只会自动映射简单、没有嵌 套的结果。FULL会自动映射任意复杂的结果(嵌套的或其他情况) -->
    <setting name="autoMappingBehavior" value="PARTIAL" />
    <!-- 配置默认的执行器。SIMPLE执行器没有什么特别之处。REUSE执行器重用预处理 语句。BATCH执行器重用语句和批量更新 -->
    <setting name="defaultExecutorType" value="SIMPLE" />
    <!-- 设置超时时间,它决定驱动等待一个数据库响应的时间 -->
    <setting name="defaultStatementTimeout" value="25000" />
    <!-- 允许在嵌套语句中使用分页(RowBounds)默认false -->
    <setting name="safeRowBoundsEnabled" value="false" />
    <!-- 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名
A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。默认false -->
    <setting name="mapUnderscoreToCamelCase" value="false" />
    <!-- MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular
references)和加速重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执 行的所有查询。 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同
SqlSession 的不同调用将不会共享数据。 -->
    <setting name="localCacheScope" value="SESSION" />
    <!-- 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需 要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。
-->
    <setting name="jdbcTypeForNull" value="OTHER" />
    <!-- 指定对象的哪个方法触发一次延迟加载。 -->
    <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode
,toString" />
    <!-- CGLIB | JAVASSIST 默认JAVASSIST(MyBatis 3.3 or above) -->
    <!-- 指定 Mybatis 创建具有延迟加载能力的对象所用到的代理工具。 -->
    <setting name="proxyFactory" value="JAVASSIST" />
    <!-- 当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之, 每种属性将会按需加载。 -->
    <setting name="aggressiveLazyLoading" value="true" />
    <!-- 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 -->
    <setting name="logImpl" value="LOG4J " />
    <!-- 指定 MyBatis 增加到日志名称的前缀。值可以是任意字符串 -->
    <setting name="logPrefix" value="LOG4J " />
    <!-- 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为
put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。注意基本类 型(int、boolean等)是不能设置成 null 的。 默认false-->
    <setting name="callSettersOnNulls" value="false " />
</settings>
  • mappers元素
<mappers>
    <mapper resource="com/mappers/StudentMapper.xml" />
    <mapper url="file:///D:/mybatisdemo/app/mappers/StudentMapper.xml" />
    <mapper class="com.pojo.StudentMapper" />
    <package name="com.mappers" />
</mappers>
  1. 创建实体类,dao接口和sql映射文件。
  2. 创建SqlSessionFactoryBuilder对象,需要传入mybatis-config.xml的字节流或字符流或者configuration对象,该对象的作用只有一个,那就是获取SqlSessionFactory对象,SqlSessionFactory对象的作用域为Application,即整个程序运行的阶段。调用SqlSessionFactory的openSession方法可以获取SqlSession对象。SqlSession对象的作用相当于Connection对象。使用后需要关闭连接。

映射文件的配置

insert

表示对应的接口方法为插入

如果插入对象的主键生成策略为自增长主键需要手动配置

<insert id="insertStudent" parameterType="Student"
	 useGeneratedKeys="true" keyProperty="studId">
	 INSERT INTO STUDENTS(NAME, EMAIL, PHONE)
	 VALUES(#{name},#{email},#{phone})
</insert>

自增长的主键会自动注入对象中的属性,但是有些数据库不支持自增长主键,比如Oracle,需要用下面这种方式。

<insert id="insertStudent" parameterType="Student">
	<selectKey keyProperty="studId" resultType="int" order="BEFORE">
 		SELECT my_seq.nextval FROM DUAL
 	</selectKey>
 	INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL, PHONE)
 	VALUES(#{studId},#{name},#{email},#{phone})
</insert>

update

表示对应的接口方法为修改

delete

表示对应的接口方法为删除

select

表示对应的接口方法为查询

传入参数 parameterType和resultType
MyBatis强大之处在于映射SELECT查询结果到java的各种类型。包括Collection和Map.
对于List,Collection,Iterable类型,MyBatis将返java.util.ArrayList
对于Map类型,MyBatis 将返回java.util.HashMap
对于Set类型,MyBatis 将返回java.util.HashSet
对于SortedSet类型,MyBatis将返回java.util.TreeSet

ResultMap:

ResultMap被用来将SELECT语句的结果集映射到java对象的属性中。我们可以定义结果集映射ResultMaps并且在一些SELECT语句上引用resultMap。MyBatis的结果集映射 ResultMaps特性非常强大,你可以使用它将简单的SELECT语句映射到复杂的一对一、一对多关系的SELECT语句上。
resultMap的id值应该在此名空间内是唯一的,并且type属性是完全限定类名或者是返回类型的别名。< result >子元素被用来将一个resultset列映射到对象的一个属性中。< id >元素和< result >元素功能相同,不过< id >它被用来映射到唯一标识属性,用来区分和比较对象(一般和主键列相对应)

<resultMap id="StudentResult" type="com.pojo.Student">
	<id property="studId" column="stud_id" />
	<result property="name" column="name" />
	<result property="email" column="email" />
	<result property="phone" column="phone" />
</resultMap>

拓展resultMap,有时resultMap中映射的元素不够,而我们为了节省代码量,可以使用resultMap的extends属性,拓展出一个新的resultMap。

一对一映射

  1. 使用嵌套resultMap
<!-- 独立的Address封装映射 -->
<resultMap type="Address" id="AddressResult">
	<id property="addrId" column="addr_id" />
 	<result property="street" column="street" />
 	<result property="city" column="city" />
	<result property="state" column="state" />
	<result property="zip" column="zip" />
	<result property="country" column="country" />
</resultMap>
<!-- Student封装映射,里面关联上Address的封装映射 -->
<resultMap type="Student" id="StudentWithAddressResult">
	<id property="studId" column="stud_id" />
  	<result property="name" column="name" />
  	<result property="email" column="email" />
  	<result property="dob" column="dob" />
  	<result property="phone" column="phone" />
  	<association property="address" resultMap="AddressResult" />
</resultMap>

< association > 是关联的意思,常被用来表示(has-one)类型的关联。就是对象1里面关联另一个对象2

  1. 使用嵌套查询
<!-- 独立的Address封装映射 -->
<resultMap type="Address" id="AddressResult">
	<id property="addrId" column="addr_id" />
  	<result property="street" column="street" />
  	<result property="city" column="city" />
  	<result property="state" column="state" />
  	<result property="zip" column="zip" />
  	<result property="country" column="country" />
</resultMap>
<!-- 独立的select查询,专门查询Address -->
<select id="findAddressById" parameterType="int" resultMap="AddressResult">
 select * from addresses
 where addr_id=#{id}
</select>
<!-- Student封装映射,里面关联了查询address使用的select语句,并指定数据库表中的 这个关联的外键列的名字,这里是addr_id -->
<resultMap type="Student" id="StudentWithAddressResult">
	<id property="studId" column="stud_id" />
  	<result property="name" column="name" />
  	<result property="email" column="email" />
  	<result property="dob" column="dob" />
  	<result property="phone" column="phone" />
  	<association property="address" column="addr_id"
select="findAddressById" />
</resultMap>
<!-- 查询Student的select语句,这里不用写多表查询,因为对于address的关 联查询,已经在上边定义好了,并且在结果映射中关联进来了 -->
<select id="selectStudentWithAddress" parameterType="int"
resultMap="StudentWithAddressResult">
 select * from students
 where stud_id=#{id}
</select>

在此方式中, < association >元素的select属性被设置成了id为findAddressById的语句。两个分开的SQL语句将会在数据库中分别执行,第一个通过id查询student信息,而第二个调用findAddressById来加载address信息。addr_id列的值将会被作为输入参数传递给selectAddressById语句作为参数进行条件查询。

一对多映射

< collection > 标签可以用来将多行课程结果映射成一个课程Course对象的集合。和之前的一对一映射一样,可以使用【嵌套结果】ResultMap和【嵌套查询】Select语句两种方式映射实现一对多映射。

  1. 使用嵌套结果
<!-- 独立的Address封装映射 -->
<resultMap type="Address" id="AddressResult">
	<id property="addrId" column="addr_id" />
  	<result property="street" column="street" />
  	<result property="city" column="city" />
  	<result property="state" column="state" />
  	<result property="zip" column="zip" />
  	<result property="country" column="country" />
</resultMap>
<!-- 独立的Course封装映射 -->
<resultMap type="Course" id="CourseResult">
	<id column="course_id" property="courseId" />
	<result column="name" property="name" />
	<result column="description" property="description" />
	<result column="start_date" property="startDate" />
	<result column="end_date" property="endDate" />
</resultMap>
<!-- Tutor封装映射,里面是有嵌套结果的方式关联一个Addres和多个Course,分别 使用association标签和collection标签 -->
<resultMap type="Tutor" id="TutorResult">
	<id column="tutor_id" property="tutorId" />
  	<result column="name" property="name" />
  	<result column="email" property="email" />
  	<result column="phone" property="phone" />
  	<association property="address" resultMap="AddressResult" />
  	<collection property="courses" resultMap="CourseResult" />
</resultMap> 
<!-- 查询Tutor的select语句,多表连接查询,把查询的结果给个上面的映射结果统 一进行封装 -->
<select id="findTutorById" parameterType="int"
resultMap="TutorResult">
 select
 t.tutor_id, t.name, t.email,t.phone,
 c.course_id, c.name, c.description, c.start_date,
c.end_date,
 a.addr_id,a.street,a.city,a.state,a.zip,a.country
 from
 tutors t
 left outer join addresses a on t.addr_id = a.addr_id
 left outer join courses   c on t.tutor_id = c.tutor_id
 where
 t.tutor_id=#{id}
</select>
  1. 使用嵌套查询
<!-- 独立的Address封装映射 -->
<resultMap type="Address" id="AddressResult">
	<id property="addrId" column="addr_id" />
	<result property="street" column="street" />
	<result property="city" column="city" />
  	<result property="state" column="state" />
  	<result property="zip" column="zip" />
  	<result property="country" column="country" />
</resultMap>
<!-- 独立的Course封装映射 -->
<resultMap type="Course" id="CourseResult">
	<id column="course_id" property="courseId" />
  	<result column="name" property="name" />
  	<result column="description" property="description" />
  	<result column="start_date" property="startDate" />
  	<result column="end_date" property="endDate" />
</resultMap>
<!-- Tutor封装映射,里分别使用association和collection标签来进行关联查询, 直接把对应的select查询语句管理进行 -->
<resultMap type="Tutor" id="TutorResult">
	<id column="tutor_id" property="tutorId" />
  	<result column="tutor_name" property="name" />
  	<result column="email" property="email" />
  	<result column="phone" property="phone" />
  	<!-- 把addr_id列的值当做参数传给findAddressById进行查询 -->
  	<association property="address" column="addr_id"
select="findAddressById"></association>
  	<!-- 把tutor_id列的值当做参数传给findCoursesByTutor进行查询 -->
  	<collection property="courses" column="tutor_id"
select="findCoursesByTutor" />
</resultMap> 
<!-- 单独的Tutor查询语句 -->
<select id="findTutorById" parameterType="int"
resultMap="TutorResult">
 select *  
 from tutors
 where tutor_id=#{tutor_id}
</select>
<!-- 单独的Address查询语句 -->
<select id="findAddressById" parameterType="int"
resultMap="AddressResult">
 select *
 from addresses
 where addr_id = #{addr_id}
</select>
<!-- 单独的Course查询语句 -->
<select id="findCoursesByTutor" parameterType="int"
resultMap="CourseResult">
   select *
   from courses
   where tutor_id=#{tutor_id}
</select>

多对多映射

<?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.mappers.Many2ManyMapper">
<insert id="insertStudent"
parameterType="com.many2many.Student">
	<selectKey keyProperty="id" resultType="int"
 order="BEFORE">
 		select my_seq.nextval from dual
 	</selectKey>
 	insert into
 	student(id,name,gender,major,grade)
 	values
 (#{id},#{name},#{gender},#{major},#{grade})
</insert>
<insert id="insertCourse"
parameterType="com.many2many.Course">
 	<selectKey keyProperty="id" resultType="int"
order="BEFORE">
 		select my_seq.nextval from dual
 	</selectKey>
 	insert into
 	course(id,course_code,course_name)
 	values
 	(#{id},#{courseCode},#{courseName})
</insert>
<select id="getStudentById" parameterType="int"
 resultType="com.many2many.Student">
 select id,name,gender,major,grade
 from student
 where id=#{id}
</select>
<select id="getCourseById" parameterType="int"
 resultType="com.many2many.Course">
 select id,course_code as courseCode,course_name as
courseName
 from course
 where id=#{id}
</select>
<!-- param1代表方法中第一个参数 以此类推 -->
<insert id="studentSelectCourse">
 insert into
 student_course(id,student_id,course_id)
 values
 (my_seq.nextval,#{param1.id},#{param2.id})
</insert>
 <!-- 如果有特殊符号的话 需要用 <![CDATA[ 特殊符号 ]]> 例如 < & 等等 -->
<select id="getStudentByIdOnCondition" parameterType="int"
 resultType="com.many2many.Student">
 select *
 from student
 where id <![CDATA[ < ]]>
 #{id}
</select>
<!-- 这里使用了嵌套结果ResultMap的方式进行级联查询 当然也可以使用嵌套查 询select -->
<!-- 映射一个基本的Student查询结果 -->
<resultMap id="StudentResult"
type="com.many2many.Student">
 <id property="id" column="id" />
 <result property="name" column="name" />
 <result property="gender" column="gender" />
 <result property="major" column="major" />
 <result property="grade" column="grade" />
</resultMap>
 <!-- 继承上面那个基本的映射,再扩展出级联查询 -->
<resultMap id="StudentResultWithCourses"
type="com.many2many.Student"
 extends="StudentResult">
 <collection property="courses" resultMap="CourseResult">
 </collection>
</resultMap>
 <!-- 这里特别注意的是column="cid" 这是和select语句中的 c.id as cid对 应的 -->
<resultMap id="CourseResult" type="com.many2many.Course">
 <id property="id" column="cid" />
 <result property="courseCode" column="course_code" />
 <result property="courseName" column="course_name" />
</resultMap>
<!-- 注意:查询语句的中的c.id as cid这个地方,避免名字相同出现查询结果不 正确的情况 同时在id="CourseResult"的resultMap中也有与这里对应的设置要特别特别 注意 -->
<select id="getStudentByIdWithCourses" parameterType="int"
 resultMap="StudentResultWithCourses">
 select s.id,s.name,s.gender,s.major,s.grade,c.id as
 
cid,c.course_code,c.course_name,sc.id,sc.student_id,sc.course_id
 from student s,course c,student_course sc
 where
 s.id=#{id}
 and
 s.id = sc.student_id
 and
 c.id = sc.course_id
</select>
</mapper>

  1. ORM全称对象关系映射,即在对象模型(JavaBean)和关系型数据库之间建立起对应的联系 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值