MyBatis


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

官方文档:http://www.mybatis.org/mybatis-3/zh/index.html

入门

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。

XML 配置文件

<?xml version="1.0" encoding="UTF-8"?>
 <!-- XML 头部的声明,验证 XML 文档正确性 -->
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
	<!-- 类型别名 -->
	<typeAliases>
		<typeAlias alias="User" type="com.offcn.bean.User"/>
		<typeAlias alias="Car" type="com.offcn.bean.Car"/>
	</typeAliases>
	<!-- mybatis 主环境的配置 -->
	<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:///user" />
				<property name="username" value="root" />
				<property name="password" value="1234" />
			</dataSource>
		</environment>
	</environments>
	<!-- 映射器 -->
	<mappers>
		<!-- 映射器的 XML 映射文件包含了 SQL 代码和映射定义信息 -->
		<mapper resource="com/offcn/mapper/UserMapper.xml" />
		<mapper resource="com/offcn/mapper/CarMapper.xml" />
	</mappers>
</configuration>

XML 映射文件

对应接口中不同的参数形式,sql语句中参数的写法不同

<?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 命名空间 区分同名的定义 多个mapper中如果出现的同名的方法的时候,我们可以使用命名空间区分 -->
<mapper namespace="com.offcn.mapper.UserMapper">
	<!-- insert : 插入操作 
	id: 属性中的方法名称必须和接口中的方法名称保持一致 
	parameterType: 方法的参数类型 -->
	<insert id="saveUser" parameterType="User"><!-- 参数为对象 -->
		<!-- 
			selectKey: 执行sql语句获取返回值.并将返回值设置为目标对象的属性
			keyProperty: selectKey 语句结果返回应该被设置的目标属性
			keyColumn: 匹配属性的返回结果集中的列名称
			resultType: 返回类型
			order: BEFORE  AFTER   : sql和返回值获取的先后关系 
		-->  
		<selectKey keyProperty="uid" keyColumn="uid" resultType="int" order="AFTER">
			select last_insert_id();
		</selectKey>
		<!-- 执行的sql #{传入类型的属性名称}占位符 和jdbc中 ? 一样 -->
		insert into user(uid,uname,pwd) values(#{uid},#{uname},#{pwd});
	</insert>
	
	<select id="moreParamTest1" resultType="User"><!-- 数组下标 -->
		select * from user where uid=#{0} and uname=#{1}
	</select>
	<select id="moreParamTest2" parameterType="java.util.Map" resultType="User"><!-- 参数为Map -->
		select * from user where uid=#{uid} and uname=#{uname}
	</select>
	<select id="moreParamTest3" resultType="User"><!-- 参数为注解 -->
		select * from user where uid=#{uid} and uname=#{uname}
	</select>
</mapper>

接口

public interface UserMapper {
	//参数为对象
	public int saveUser(User user);
	//参数为参数列表,对应映射文件中用数组下标
	public User moreParamTest1(int uid,String uname);
	//参数为Map集合 通过K-V确定
	public User moreParamTest2(Map<String,Object> map);
	//参数为注解 别名形式
	public User moreParamTest3(@Param("uid")int uid,@Param("uname")String uname);
}

从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但是也可以使用任意的输入流(InputStream)实例,包括字符串形式的文件路径或者 file:// 的 URL 形式的文件路径来配置。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,可使从 classpath 或其他位置加载资源文件更加容易。

简单应用

package com.offcn.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

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.junit.Test;

import com.offcn.bean.Car;
import com.offcn.bean.User;
import com.offcn.mapper.CarMapper;
import com.offcn.mapper.UserMapper;


/**
 * @author ZJT
 * mybatis 
 */
public class TestMybatis {

	/**
	 * 简单入门||一般流程
	 */
	@Test
	public void run() {
		// 读取配置文件(是否将mapper.xml加入到主配置中)
		try {
			// 使用输入流读取外部的mybatis的配置文件
			InputStream is = Resources.getResourceAsStream("MybatisConfig.xml");
			// 构建session工厂
			SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(is);
			// 构建session
			SqlSession session = sf.openSession();
			// 获取接口对象
			UserMapper mapper = session.getMapper(UserMapper.class);
			// 准备数据
			User user = new User();
			user.setUname("王五");
			user.setPwd("123");
			// 接口对象调用方法
			mapper.saveUser(user);
			// 提交session
			session.commit();
			// 关闭session
			session.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**
	 * 多参数处理||数组下标
	 */
	@Test
	public void run1() {
		// 读取配置文件(是否将mapper.xml加入到主配置中)
		try {
			InputStream is = Resources.getResourceAsStream("MybatisConfig.xml");
			SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(is);
			SqlSession session = ssf.openSession();
			UserMapper mapper = session.getMapper(UserMapper.class);
			
			User user = mapper.moreParamTest1(7,"王五");
			System.out.println(user);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**
	 * 多参数处理||Map
	 */
	@Test
	public void run2() {
		// 读取配置文件(是否将mapper.xml加入到主配置中)
		try {
			InputStream is = Resources.getResourceAsStream("MybatisConfig.xml");
			SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(is);
			SqlSession session = ssf.openSession();
			UserMapper mapper = session.getMapper(UserMapper.class);
			
			Map<String,Object> map = new HashMap<>();
			map.put("uid", 7);
			map.put("uname", "王五");
			
			User user = mapper.moreParamTest2(map);
			System.out.println(user);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**
	 * 多参数处理||注解
	 */
	@Test
	public void run3() {
		// 读取配置文件(是否将mapper.xml加入到主配置中)
		try {
			InputStream is = Resources.getResourceAsStream("MybatisConfig.xml");
			SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(is);
			SqlSession session = ssf.openSession();
			UserMapper mapper = session.getMapper(UserMapper.class);
			
			User user = mapper.moreParamTest1(7,"王五");
			System.out.println(user);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**
	 * 插入表时返回一字段封入对象对应属性
	 */
	@Test
	public void run4() {
		// 读取配置文件(是否将mapper.xml加入到主配置中)
		try {
			InputStream is = Resources.getResourceAsStream("MybatisConfig.xml");
			SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(is);
			SqlSession session = ssf.openSession();
			UserMapper mapper = session.getMapper(UserMapper.class);
			User user = new User();
			user.setUname("张三");
			user.setPwd("666");
			mapper.saveUser(user);
			System.out.println(user);
			
			CarMapper carMapp = session.getMapper(CarMapper.class);
			Car car = new Car(user.getUid(), "宝马");
			carMapp.saveCar(car);
			System.out.println(car);
			
			// 提交session
			session.commit();
			// 关闭session
			session.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
}

ResultMap

基础属性

结果映射.ResultMap 的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系

当类中属性名称和表中字段名称不一致时属性是无法封进去的

<mapper namespace="com.offcn.mapper.UserMapper">
	<select id="getUserById" parameterType="User" resultType="User">
		select * from user where uid=#{uid}
	</select>
</mapper>

在这里插入图片描述

resultMap 基本设置

<mapper namespace="com.offcn.mapper.UserMapper">
	<!-- 1.解决类中属性名称和表中字段名称不一致
		type 类的完全限定名, 或者一个类型别名
		id 当前命名空间中的一个唯一标识,用于标识一个结果映射
	 -->
	<resultMap type="User" id="newUser">
		<!-- id 和 result 元素都将一个列的值映射到一个简单数据类型的属性或字段
			两者之间的唯一不同是,id 元素表示的结果将是对象的标识属性 -->
		<id column="uid" property="uid"/><!-- property 映射到列结果的字段或属性 -->
		<result column="uname" property="name"/><!-- column 数据库中的列名,或者是列的别名 -->
		<result column="pwd" property="pwd"/>
	</resultMap>
	<select id="getUserById" parameterType="User" resultMap="newUser">
		select * from user where uid=#{uid}
	</select>
</mapper>

关联元素 || 一对一多表查询

第一种写法

	<!-- 2.一对一多表查询 -->
	<!-- 基础resultMap,共用的可提取出来 -->
	<resultMap type="User" id="newUser">
		<id column="uid" property="uid"/>
		<result column="uname" property="name"/>
		<result column="pwd" property="pwd"/>
		
		<!-- 2.1版本 一对一多表查询.这样写复用性差 -->
		<!-- 关联(association)元素处理“有一个”类型的关系.你需要指定目标属性名以及属性的javaType
			很多时候 MyBatis 可以自己推断出来.column很多时候可以省略不写 -->
		<association column="uid" property="card" javaType="Card">
			<id column="uid" property="cid"/>
			<result column="cname" property="cname"/>
		</association>
	</resultMap>

需要将Card封入User作为属性
在这里插入图片描述

第二种写法
关联的嵌套结果映射

	<resultMap type="User" id="newUser">
		<id column="uid" property="uid"/>
		<result column="uname" property="name"/>
		<result column="pwd" property="pwd"/>
	</resultMap>
	
	<!-- 2.2一对一查询  继承扩展  关联的嵌套结果映射
		用了外部的结果映射元素来映射关联。这使得结果映射可以被重用
	-->
	<resultMap type="User" id="newUser1" extends="newUser">
		<!-- resultMap  结果映射的 ID-->
		<association property="card" javaType="Cadr" 
			resultMap="com.offcn.mapper.CardMapper.newCard">
		</association>
	</resultMap>
	
	<select id="getUserAndCard" parameterType="User" resultMap="newUser1">
		select u.*,c.* from user u,card c where u.uid=c.uid and u.uid=#{uid}
	</select>

其它xml映射文件中被调用的.这样相同写法的resultMap可提取出来,需要的时候通过resultMap=" "调取即可

<?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.offcn.mapper.CardMapper">
	<!-- 基础resultMap,共用的可提取出来-->
	<resultMap type="Card" id="newCard">
		<id column="cid" property="cid"/>
		<result column="cname" property="cname"/>
	</resultMap>
</mapper>

第三种写法

查询当前的person对象的时候,我们调用其他的mapper.xml配置文件的中已经写好的select查询(查询出当前对象的时候不想要去立即查询关联对象,只有等到我们想要去使用关联对象的时候在去发送我们sql),将我们的sql进行拆分

	<!-- 2.3一对一查询 关联的嵌套 Select 查询
		select 用于加载复杂类型属性的映射语句的 ID,
		它会从 column 属性指定的列中检索数据,作为参数传递给目标 select 语句
		缺点:在大型数据集或大型数据表上表现不佳。这个问题被称为“N+1 查询问题”
	 -->
	<resultMap type="User" id="newUser2" extends="newUser">
		<association column="uid" property="card" javaType="Card" 
		select="com.offcn.mapper.CardMapper.getCardById"></association>
	</resultMap>
	
	<select id="getUserById" parameterType="User" resultMap="newUser2">
		select * from user where uid=#{uid}
	</select>
<mapper namespace="com.offcn.mapper.CardMapper">
	<resultMap type="Card" id="newCard">
		<id column="cid" property="cid"/>
		<result column="cname" property="cname"/>
	</resultMap>
	<!-- 被引用的查询 -->
	<select id="getCardById" parameterType="Card" resultMap="newCard">
		select * from card where uid=#{uid}
	</select>
</mapper>

集合元素 || 一对多多表查询

集合元素和上文关联元素几乎是一样的,它们相似的程度之高,以致于没有必要再介绍集合元素的相似部分。 仅关注它们的不同之处.这里仅介绍一种写法,其它参照关联元素的写法即可.
新加的是集合元素。 里面有新的 “ofType” 属性。这个属性非常重要,它用来将 JavaBean(或字段)属性的类型和集合存储的类型区分开来.

	<!-- ofType="Car"  是一个存储 Car 的集合”. -->
	<resultMap type="User" id="newUser5" extends="newUser">
		<collection column="uid" property="cars" ofType="Car" 
		select="com.offcn.mapper.CarMapper.getCarById"></collection>
	</resultMap>
	<select id="getUserById" parameterType="User" resultMap="newUser5">
		select * from user where uid=#{uid}
	</select>

被调用的 select id=“getCarById”

<mapper namespace="com.offcn.mapper.CarMapper">
	<resultMap type="Car" id="newCar">
		<id column="cid" property="cid"/>
		<result column="cname" property="cname"/>
	</resultMap>
	<select id="getCarById" parameterType="Car" resultMap="newCar">
		select * from car where uid=#{uid}
	</select>
</mapper>

动态SQL

逆向工程

MyBatis的一个主要的特点就是需要程序员自己编写sql,那么如果表太多的话,难免会很麻烦,所以mybatis官方提供了一个逆向工程,可以针对单表自动生成mybatis执行所需要的代码(包括mapper.xml、mapper.java、po…)。一般在开发中,常用的逆向工程方式是通过数据库的表生成代码

官方文档:http://www.mybatis.org/generator/

运行方式

在这里插入图片描述

配置文件\jar包等

1.需要导入的jar包

在这里插入图片描述

2.配置文件

主要设置以下信息
连接数据库
指定要生成代码的位置,要生成的代码包括po类,mapper.xml和mapper.java
指定数据库中想要生成哪些表

注意:配置文件最好和src同级放置. targetPackage=""路径指定后会在生成代码后自动创建

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>

	<context id="DB2Tables" targetRuntime="MyBatis3">

		<commentGenerator>
			<!-- 是否去除自动生成的注释 true:是 : false:-->
			<property name="suppressAllComments" value="true"></property>
		</commentGenerator>


		<!-- 设定数据库连接的基本信息 -->
		<jdbcConnection driverClass="com.mysql.jdbc.Driver"
			connectionURL="jdbc:mysql://localhost:3306/user" userId="root"
			password="1234">
		</jdbcConnection>

		<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 
			和 NUMERIC 类型解析为java.math.BigDecimal -->
		<javaTypeResolver>
			<property name="forceBigDecimals" value="false" />
		</javaTypeResolver>

		<!-- targetProject:生成PO类的位置 -->
		<javaModelGenerator targetPackage="com.offcn.bean"
			targetProject=".\src">
			<!-- enableSubPackages:是否让schema作为包的后缀 -->
			<property name="enableSubPackages" value="true" />
			<!-- 从数据库返回的值清理前后的空格 -->
			<property name="trimStrings" value="true" />
		</javaModelGenerator>

		<!-- mapper映射文件的位置  -->
		<sqlMapGenerator targetPackage="com.offcn.mapper"
			targetProject=".\src">
			<property name="enableSubPackages" value="true" />
		</sqlMapGenerator>

		<!-- .xml对应的mapper接口的位置 -->
		<javaClientGenerator type="XMLMAPPER"
			targetPackage="com.offcn.mapper" targetProject=".\src">
			<property name="enableSubPackages" value="true" />
		</javaClientGenerator>

		<!-- 设定逆向生成的表 -->
		<table tableName="user"></table>
		<table tableName="card"></table>

	</context>
</generatorConfiguration>

3.基于XML的配置的逆向生成代码

在这里插入图片描述

最后运行生成即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值