前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MyBatis基础入门

MyBatis基础入门

作者头像
用户10175992
发布2022-11-15 13:40:07
3850
发布2022-11-15 13:40:07
举报
文章被收录于专栏:辰远

1. 持久化与ORM技术

1.1 持久化

在软件开发过程中,我们经常要把程序内存中的数据存放到磁盘(或数据库),或者把磁盘(或数据库)的数据加载到内存。这种把程序数据在“瞬时状态”和“持久状态”间转换的过程我们称之为“持久化”。

1.2 ORM

我们往往使用“关系型数据库”来持久化有一定复杂度的程序数据,在Java中,这种持久化是使用JDBC来实现的。用过JDBC的人都知道,JDBC的代码重复性很高,而且冗余代码很多,特别是从ResultSet到对象的相互转换上。有没有更高效的方式来简化这些持久化操作呢?有的,这就是所谓的ORM(Object Relaction Mapping)技术。

        ORM,就是对象关系映射,我们通过一些配置方式,把对象和关系型数据库表的结构一一对应起来,这样只要编写少量的查询语句(比如SQL),我们就可以让程序制动化的把SQL执行结果填充到对象中,免去了编写大量的JDBC代码。Java最常用的ORM框架就是Hibernate和MyBatis。

1.3 MyBatis简介

1.3.1 Hibernate与MyBatis

Hibernate是Java平台上的ORM老大哥,非常自动化,几乎不用编写任何的SQL语句就可以实现常见的CURD操作甚至是复杂查询。但Hibernate也有它的弊端,就是模型复杂,学习成本高,由于可以不编写SQL,因此性能有可控性有些差,要用好它不是一件容易的事。

MyBatis是Java平台上ORM的后起之秀,模型简单,学习成本非常低,性能可控性很高。但相比Hibernate而言,MyBatis的所有数据库操作都要自己写SQL语句,因此代码量比Hibernate要高一些,但相对于原生的JDBC还是有很高的开发效率。

1.3.2 MyBatis的相关资料

官方文档:mybatis – MyBatis 3 | 简介

        官方源码:https://github.com/mybatis/mybatis-3

2 试用MyBatis框架

        下面以Sqlserver数据库作为示范来讲解MyBatis的使用。

2.1 在项目中导入MyBatis框架jar包

        使用MyBatis开发数据访问层,只需要导入mybatis-3.x.x.jar和对应的JDBC驱动即可。以下使用两种方式导入相关依赖。

(1)直接导入

(2)使用Maven

代码语言:javascript
复制
<dependencies>
		<!-- JDBC MySQL 驱动 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.8</version>
		</dependency>
		<!-- MyBatis 核心依赖 -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.2.5</version>
		</dependency>	
</dependencies>

2.2 设置MyBatis框架的配置信息

MyBatis框架需要两种配置文件:“主配置文件”和“查询映射配置文件”。

主配置文件(mybatis.xml),用于配置“数据库会话工厂”,主要作包括:1)数据库连接(连接池)信息;2)指定其他查询映射配置文件的位置。

查询映射配置文件(CategoryMapper.xml),一般用于配置某实体类(Category.java)的CURD操作所涉及的SQL语句。

如果是Maven项目,这些配置信息都应该放在Resources目录中。

(1)创建“MyBatis主配置文件”

        在“类目录”下创建名为mybatis.xml(文件名可自定)的文件,配置内容如下:

代码语言:javascript
复制
<?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.jdbc.Driver" />
				<property name="url" value="jdbc:mysql://localhost:3306/MyCinema" />
				<property name="username" value="root" />
				<property name="password" value="1234" />
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<mapper resource="mapper/CategoryMapper.xml" />
	</mappers>
</configuration>

其中,“property”包裹部份用于配置数据库的连接信息(JDBC驱动、数据库url、用户名和密码);而“蓝色字体”部分用于指定针对实体类的查询映射配置文件的位置。

(2)创建查询映射配置文件

        创建数据实体类Category.java和实体映射文件CategoryMapper.xml。

        以下实体类表示电影分类,与数据库的Category表对应。

代码语言:javascript
复制
public class Category {
	private int id;
	private String name;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

Category的查询映射文件的结构如下所示:

代码语言:javascript
复制
<?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="mycinema.dao.CategoryMapper">
  	<select id="fetchById" parameterType="int" resultType="mycinema.entity.Category">
    	select * from Category where id=#{id}
  	</select>
</mapper>

每添加一个实体配置文件,就应该在主配置文件(mybatis.xml)中加入一个<mapper>元素,以告知框架要把该实体加入到映射中,详见上一节mybatis.xml配置中的蓝色字体部份。

注意点:

1)mapper元素的namespace与select元素的id共同决定了一个SQL语句的“坐标”,在MyBatis框架执行查询时,使用坐标标识所调用的SQL

2)SQL语句中的参数通过“#{参数名}”的方式声明,而参数类型需要通过select元素的parameterType来声明

3)select元素通过resultType来声明返回类型(实体对象)

2.3 创建MyBatis数据库会话(SqlSession)并执行查询

代码语言:javascript
复制
InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();
try {
	Category c = (Category)session.selectOne("mycinema.dao.CategoryMapper.fetchById",1);
	System.out.println(c.getName());
} finally {
	session.close();
}

注意:

        1)SqlSessionFactoryBuilder对象:用于构建SqlSessionFactory,此后这个类就不需要存在了。因此SqlSessionFactoryBuilder实例的最佳范围是方法范围 (也就是本地方法变量)。

        2)SqlSessionFactory对象:一旦被创建,应该在你的应用执行期间都存在。没有理由释放或重新创建它。使用SqlSessionFactory的最佳实践是在应用运行期间不要重复创建多次,因此 SqlSessionFactory 的最佳范围是应用范围,最简单的就是使用单例模式或者静态单例模式。

        3)SqlSession对象:每个线程都应该有它自己的SqlSession实例。SqlSession 的实例不能被共享,它是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将 SqlSession 实例的引用放在一个类的静态字段甚至是实例字段中。如果你在使用Web框架,则要考虑把SqlSession 放在一个和HTTP请求对象相似的范围内(Open Session In View)。关闭 Session 很重要,你应该确保使 用 finally 块来关闭它。下面的示例就是一个确保 SqlSession 关闭的基本模式:

代码语言:javascript
复制
SqlSession session = sqlSessionFactory.openSession();
try {
  		// do work
} finally {
		session.close();
}

对于增删改的操作,需要使用SqlSession的commit方法实现提交:

代码语言:javascript
复制
SqlSession session = sqlSessionFactory.openSession();
try {
  		// do work
		session.commit();	//增删改需要提交事务
} finally {
		session.close();
}

4)SqlSession的selectOne方法表示查询返回单一对象;如果返回的是多个对象的集合,应使用selectList方法;这些数据库操作方法的第一个参数都是String,该String值指定了要操作的SQL语句的坐标(即SQL查询映射文件中配置的“mapper元素的namespace+select元素的id”)。

5)SqlSession的insert()、delete()和update()方法则分别对应于配置文件的<insert>、<delete>、<update>元素,完整的配置信息参考如下。

代码语言:javascript
复制
<?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="mycinema.dao.CategoryMapper">
  	<select id="fetchById" parameterType="int" resultType="mycinema.entity.Category">
    	select * from Category where id=#{id}
  	</select>
  	<select id="getAll" resultType="mycinema.entity.Category">
    	select * from Category
  	</select>
	<insert id="add" parameterType="mycinema.entity.Category">
		insert into Category(name) values(#{name})
	</insert>
	<update id="update" parameterType="mycinema.entity.Category">
		update Category set name=#{name} where id=#{id}
	</update>
	<delete id="delete" parameterType="int">
		delete from Category where id=#{id}
	</delete>
</mapper>

3 使用映射器(Mapper)接口操作SQL语句

      上述的查询中,使用映射语句“mycinema.dao.CategoryMapper.fetchById”指定要执行的SQL,这种弱类型的使用方式容易出问题:缺乏编程提示和编译检查。为此,MyBatis还提供了强类型的使用方式——映射器(Mapper)方式。

        实际上,MyBatis中所谓的“映射器”接口就是我们所说的“数据访问对象”(DAO)接口。

        该使用方式的具体做法如下:

(1)在查询配置文件CategoryMapper.xml中,把mapper元的namespace属性指定为一个映射器接口(CategoryMapper)的完全限定类名。

代码语言:javascript
复制
<?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="mycinema.dao.CategoryMapper">
  <select id="fetchById" parameterType="int" resultType="mycinema.entity.Category">
    select * from Category where id = #{id}
  </select>
</mapper>

(2)在映射器接口(mycinema.dao.CategoryMapper)中声明方法(fetchById),该方法的签名与配置文件的select元素匹配(方法名与select元素id相同,返回值类型和参数类型也必须对应)。

代码语言:javascript
复制
public interface CategoryMapper {
	public Category fetchById(int id);
}

(3)按上设置后,我们就可以通过CategoryMapper接口实现前面的查询了:

代码语言:javascript
复制
SqlSession session = factory.openSession();
try {
	CategoryMapper mapper = session.getMapper(CategoryMapper.class);
	Category c = mapper.fetchById(1);
	System.out.println(c.getName());
} finally {
	session.close();
}

这种调用方式是通过接口动态代理来实现的,并不需要为接口添加实现类。映射器的调用方式是强类型的,符合对象化思想,不容易出错,在实际中更为常用。

4. 为实体类提供别名(简称)

        上述的很多<select>元素的resultType属性都声明了实体类的完全限定名,冗长的类名实在不方便。我们可以在主配置文件的开头加入“类型别名”<typeAliases>声明,通过<typeAlias>来指定完全限定类名的简称,以简化类名的书写。

代码语言:javascript
复制
<configuration>
	<typeAliases>
		<typeAlias type="mycinema.entity.Category" alias="Category"/>
		……
	</typeAliases>
	<environments default="development">
		……
	</environments>
<configuration>

此后,在实体配置文件中,就可以使用Category这样的别名来指向实体类了。

        另外,还可以通过<package>元素,直接定义包名,所有没有指定包名的实体类,都以此为默认包。

代码语言:javascript
复制
<typeAliases>
		<package name="mycinema.entity"/>
</typeAliases>

5 插入数据后获取自动增长的主键ID

5.1 MySQL数据库中的auto_increatement实现主键自增长

        在许多数据库管理系统中(如MySQL和SQL Server),可以把在建表时把主键定义为自增长的整数,插入数据时不需要提供该主键,由数据库维护其自增长逻辑。

MyBatis查询配置中的<insert>元素可以自动实现该自增长主键获取功能,不需要额外的查询,在插入成功后自动的为实体对象(参数)赋值新的主键值。通过配置<insert>元素的useGeneratedKeys属性和keyProperty即可实现该功能,具体配置如下:

代码语言:javascript
复制
<insert id="add" parameterType="Category" useGeneratedKeys="true" keyProperty="id">
		insert into Category(name) values(#{name})
</insert>

5.2 Oracle中通过序列(sequence)实现自增长

      Oracle数据库并没有提供表字段的自增长设置,如果是整型字段,可以通过序列(sequence)来获取自增长值,再插入到数据库中。

        以下示例假设Oracle数据库中有一个名为seq_cinema_cate的序列,演示了如何实现插入自增长并返回自增长ID。

代码语言:javascript
复制
<insert id="add" parameterType="Category">
		<selectKey keyProperty="id" order="BEFORE" resultType="int">
			select seq_cinema_cate.nextval from dual
		</selectKey>
		insert into Category(id, name) values(#{id}, #{name})
</insert>

6 使用jdbc.properties配置数据源

在主配置文件中,数据库连接信息可以硬编码在配置中,也可以通过<properties resource="jdbc.properties" />元素,在外部以properties文件方式提供,我们在mybatis中可以用以下方式引用properties中的配置。

代码语言:javascript
复制
<properties resource="jdbc.properties"/>
	<typeAliases>…</typeAliases>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="${jdbc.driver}" />
				<property name="url" value="${jdbc.url}" />
				<property name="username" value="${jdbc.username}" />
				<property name="password" value="${jdbc.password}" />
			</dataSource>
		</environment>
	</environments>

其中,jdbc.properties配置文件的结构如下所示。

代码语言:javascript
复制
jdbc.driver=com.mysql.jdbc.Driver
jdbc.username=root
jdbc.password=1234
jdbc.url=jdbc:mysql://localhost:3306/MyCinema
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档