MyBatis框架使用

1 框架概述

1.1 什么是框架

可以说,一个框架是一个可复用的设计构件,它规定了应用的体系结构,阐明了整个设计、协作构件之间的依赖关系、责任分配和控制流程,表现为一组抽象类以及其实例之间协作的方法,它为构件复用提供了上下文(Context)关系。因此构件库的大规模重用也需要框架。

1.2 为什么使用框架

  • 因为软件系统发展到今天已经很复杂了,特别是服务器端软件,涉及到的知识,内容,问题太多。
  • 在某些方面使用别人成熟的框架,就相当于让别人帮你完成一些基础工作,你只需要集中精力完成系统的业务逻辑设计。
  • 而且框架一般是成熟,稳健的,它可以处理系统很多细节问题,比如,事务处理,安全性,数据流控制等问题。
  • 还有框架一般都经过很多人使用,所以结构很好,所以扩展性也很好,而且它是不断升级的,你可以直接享受别人升级代码带来的好处。
    1.3 软件开发的三层结构
    我们用三层结构主要是使项目结构更清楚,分工更明确,有利于后期的维护和升级.
    三层结构包含:表现层,业务层,持久层

2 Mybatis介绍

2.1 什么是mybatis

mybatis参考网址:http://www.mybatis.org/mybatis-3/zh/index.html

2.1.1 Mybatis是什么?

  • MyBatis是一个优秀的持久层框架,它是一个半自动化的ORM框架
  • 它对使用JDBC操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
     Mybatis的由来?
  • MyBatis 本是apache的一个开源项目iBatis
  • 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。
  • 2013年11月迁移到Github。

2.1.2 Mybatis在哪写SQL语句?如何设置SQL参数和封装查询结果?

  • Mybatis通过XML或注解的方式,将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来。
  • 并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

2.2 JDBC示例代码

public class JDBCTest {

	public static void main(String[] args) {
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;

		try {
			// 加载数据库驱动
			Class.forName("com.mysql.jdbc.Driver");

			// 通过驱动管理类获取数据库链接connection = DriverManager
			connection = DriverManager.getConnection(
                              "jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8",
	                         "root", 
                              "root"
                              );

			// 定义sql语句 ?表示占位符
			String sql = "select * from user where username = ?";
			// 获取预处理 statement
			preparedStatement = connection.prepareStatement(sql);
			
			// 设置参数,第一个参数为 sql 语句中参数的序号(从 1 开始),第二个参数为设置的
			preparedStatement.setString(1, "王五");
			// 向数据库发出 sql 执行查询,查询出结果集
			resultSet = preparedStatement.executeQuery();
			// 遍历查询结果集
			while (resultSet.next()) {
				System.out.println(
                                  resultSet.getString("id") 
                                  + " " + 
                                  resultSet.getString("username")
                     );
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 释放资源
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (preparedStatement != null) {
				try {
					preparedStatement.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (connection != null) {
				try {
					connection.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block e.printStackTrace();
				}
			}
		}
	}
}

2.3 Mybatis如何解决JDBC代码中存在的问题

1、 创建数据库连接相关操作,存在硬编码

解决方案:通过Mybatis全局配置文件,对数据库连接进行配置

2、 statement相关操作,存在硬编码

解决方案:通过Mapper映射文件,对statement相关处理进行配置。

3、 频繁开启数据库连接,会降低数据库处理性能。

解决方案:通过Mybatis全局配置文件,配置连接池。

2.4 Mybatis架构原理

我们要找出的答案就是:从XML配置文件到数据库的距离有多长?

说明:

1、 mybatis配置文件

a) SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
b) Mapper.xml,此文件作为mybatis的sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。

2、 SqlSessionFactory

通过mybatis环境等配置信息构造SqlSessionFactory,即会话工厂。

3、 sqlSession

通过会话工厂创建sqlSession即会话,程序员通过sqlsession会话接口对数据库进行增删改查操作。

4、 Executor执行器

mybatis底层自定义了Executor执行器接口来具体操作数据库,Executor接口有两个实现,一个是基本执行器(默认)、一个是缓存执行器,sqlsession底层是通过executor接口操作数据库的。

5、 Mapped Statement

它也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个select\insert\update\delete标签对应一个Mapped Statement对象,select\insert\update\delete标签的id即是Mapped statement的id。

a) Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。

b) Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

3 Mybatis入门

3.1 需求

1、根据用户id查询一个用户信息
2、根据用户名称模糊查询用户信息列表
3、添加用户
4、更新用户
5、删除用户

3.2 Mybatis开发框架搭建

1、创建maven工程:mybatis
2、POM文件

<dependencies>
		<!-- mybatis依赖 -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.4.6</version>
		</dependency>
		<!-- mysql依赖 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.35</version>
		</dependency>

		<!-- 单元测试 -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
		</dependency>
	</dependencies>

3、SqlMapConfig.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>
	<properties resource="db.properties"></properties>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="${db.driver}" />
				<property name="url" value="${db.url}" />
				<property name="username" value="${db.username}" />
				<property name="password" value="${db.password}" />
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<mapper resource="UserMapper.xml" />
	</mappers>
</configuration>
	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="test">
</mapper>

4、PO类

public class User {

	private int id;
	private String username;
	private Date birthday;
	private String sex;
	private String address;
	//getter\setter方法
}

3.3 需求实现

3.3.1 根据id查询用户信息

映射文件

<!-- 根据id获取用户信息 -->
	<select id="findUserById" parameterType="int" resultType="com.kkb.mybatis.po.User">
		select * from user where id = #{id} 
	</select>
<!-- parameterType:定义输入到sql中的映射类型,#{id}表示使用preparedstatement设置占位符号并将输入变量id传到sql。
resultType:定义结果映射类型。
#{}:相当于JDBC中的?占位符-->

测试代码

public class MybatisFirst {
	
	//会话工厂
	private SqlSessionFactory sqlSessionFactory;

	@Before
	public void createSqlSessionFactory() throws IOException {
		// 配置文件
		String resource = "SqlMapConfig.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);

		// 使用SqlSessionFactoryBuilder从xml配置文件中创建SqlSessionFactory
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

	}

	// 根据 id查询用户信息
	@Test
	public void testFindUserById() {
		// 数据库会话实例
		SqlSession sqlSession = null;
		try {
			// 创建数据库会话实例sqlSession
			sqlSession = sqlSessionFactory.openSession();
			// 查询单个记录,根据用户id查询用户信息
			User user = sqlSession.selectOne("test.findUserById", 10);
			// 输出用户信息
			System.out.println(user);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (sqlSession != null) {
				sqlSession.close();
			}
		}

	}
}

3.3.2 根据用户名模糊查询用户列表

映射文件

<!-- 自定义条件查询用户列表 -->
	<select id="findUserByUsername" parameterType="java.lang.String" 
			resultType="com.kkb.mybatis.po.User">
	   select * from user where username like '%${value}%' 
	</select>
parameterType:定义输入到sql中的映射类型,${value}表示输入参数将${value}替换,做字符串的拼接。
注意:如果是取简单数量类型的参数,括号中的参数名称必须为value
resultType:定义结果映射类型。

测试代码

// 根据用户名称模糊查询用户信息
	@Test
	public void testFindUserByUsername() {
		// 数据库会话实例
		SqlSession sqlSession = null;
		try {
			// 创建数据库会话实例sqlSession
			sqlSession = sqlSessionFactory.openSession();
			// 查询单个记录,根据用户id查询用户信息
			List<User> list = sqlSession.selectList("test.findUserByUsername", "小明");
			System.out.println(list.size());
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (sqlSession != null) {
				sqlSession.close();
			}
		}

	}

3.3.3 添加用户

映射文件

<!-- 添加用户 -->
	<insert id="insertUser" parameterType="com.kkb.mybatis.po.User">
	  insert into user(username,birthday,sex,address) 
	  values(#{username},#{birthday},#{sex},#{address})
	</insert>

测试代码

// 添加用户信息
	@Test
	public void testInsert() {
		// 数据库会话实例
		SqlSession sqlSession = null;
		try {
			// 创建数据库会话实例sqlSession
			sqlSession = sqlSessionFactory.openSession();
			// 添加用户信息
			User user = new User();
			user.setUsername("张小明");
			user.setAddress("河南郑州");
			user.setSex("1");
			user.setPrice(1999.9f);
			sqlSession.insert("test.insertUser", user);
			//提交事务
			sqlSession.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (sqlSession != null) {
				sqlSession.close();
			}
		}
	}

主键返回

<insert id="insertUser" parameterType="com.kkb.mybatis.po.User">
		<!-- selectKey将主键返回,需要再返回 -->
		<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
			select LAST_INSERT_ID()
		</selectKey>
	   insert into user(username,birthday,sex,address)
	    values(#{username},#{birthday},#{sex},#{address});
	</insert>
添加selectKey标签实现主键返回。
* keyProperty:指定返回的主键,存储在pojo中的哪个属性
* order:selectKey标签中的sql的执行顺序,是相对与insert语句来说。由于mysql的自增原理,执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为after。
* resultType:返回的主键对应的JAVA类型
* LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。

3.3.4 删除用户

映射文件

<!-- 删除用户 -->
	<delete id="deleteUserById" parameterType="int">
		delete from user where id=#{id}
	</delete>

测试代码

// 根据id删除用户
	@Test
	public void testDelete() {
		// 数据库会话实例
		SqlSession sqlSession = null;
		try {
			// 创建数据库会话实例sqlSession
			sqlSession = sqlSessionFactory.openSession();
			// 删除用户
			sqlSession.delete("test.deleteUserById",18);
			// 提交事务
			sqlSession.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (sqlSession != null) {
				sqlSession.close();
			}
		}
	}

3.3.5 修改用户

映射文件

<!-- 更新用户 -->
	<update id="updateUser" parameterType="com.kkb.mybatis.po.User">
		update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address}
		where id=#{id}
</update>

测试代码

// 更新用户信息
	@Test
	public void testUpdate() {
		// 数据库会话实例
		SqlSession sqlSession = null;
		try {
			// 创建数据库会话实例sqlSession
			sqlSession = sqlSessionFactory.openSession();
			// 添加用户信息
			User user = new User();
			user.setId(16);
			user.setUsername("张小明");
			user.setAddress("河南郑州");
			user.setSex("1");
			user.setPrice(1999.9f);
			sqlSession.update("test.updateUser", user);
			// 提交事务
			sqlSession.commit();

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (sqlSession != null) {
				sqlSession.close();
			}
		}
	}

4 Mybatis开发Dao层

4.1 原始dao开发方式

dao接口和实现类

public interface UserDao {
	public User findUserById(int id) throws Exception;
	public void insertUser(User user) throws Exception;
}

public class UserDaoImpl implements UserDao {
	//注入SqlSessionFactory
	public UserDaoImpl(SqlSessionFactory sqlSessionFactory){
		this. sqlSessionFactory = sqlSessionFactory;
	}
	
	private SqlSessionFactory sqlSessionFactory;
	@Override
	public User findUserById(int id) throws Exception {
		SqlSession session = sqlSessionFactory.openSession();
		User user = null;
		try {
			//通过sqlsession调用selectOne方法获取一条结果集
			//参数1:指定定义的statement的id,参数2:指定向statement中传递的参数
			user = session.selectOne("test.findUserById", id);
			System.out.println(user);
						
		} finally{
			session.close();
		}
		return user;
	}
	
	@Override
	Public void insertUser(User user) throws Exception {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		try {
			sqlSession.insert("insertUser", user);
			sqlSession.commit();
		} finally{
			session.close();
		}
		
	}
}

映射文件

<?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="test">
<!-- 根据id获取用户信息 -->
	<select id="findUserById" parameterType="int" resultType="com.kkb.mybatis.po.User">
		select * from user where id = #{id}
	</select>
<!-- 添加用户 -->
	<insert id="insertUser" parameterType="com.kkb.mybatis.po.User">
	<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
		select LAST_INSERT_ID() 
	</selectKey>
	  insert into user(username,birthday,sex,address) 
	  values(#{username},#{birthday},#{sex},#{address})
	</insert>
</mapper>

测试代码


private SqlSessionFactory sqlSessionFactory;
	
	@Before
	public void init() throws Exception {
		SqlSessionFactoryBuilder sessionFactoryBuilder = new SqlSessionFactoryBuilder();
		InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
		sqlSessionFactory = sessionFactoryBuilder.build(inputStream);
	}

	@Test
	public void testFindUserById() {
		UserDao userDao = new UserDaoImpl(sqlSessionFactory);
		User user = userDao.findUserById(22);
		System.out.println(user);
	}
}

4.2 mapper代理开发方式

开发规范
Mapper接口开发需要遵循以下规范:
1、 Mapper接口的类路径与Mapper.xml文件中的namespace相同。
2、 Mapper接口方法名称和Mapper.xml中定义的每个statement的id相同。
3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同。
4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同。

mapper映射文件

<?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.kkb.mybatis.mapper.UserMapper">
<!-- 根据id获取用户信息 -->
	<select id="findUserById" parameterType="int" resultType="com.kkb.mybatis.po.User">
		select * from user where id = #{id}
	</select>
</mapper>

mapper接口

/**
 * 用户管理mapper
 */
public interface UserMapper {
	//根据用户id查询用户信息
	public User findUserById(int id) throws Exception;
}

加载映射文件

<!-- 加载映射文件 -->
  <mappers>
    <mapper resource="mapper/UserMapper.xml"/>
  </mappers>

测试代码

public class UserMapperTest{

	private SqlSessionFactory sqlSessionFactory;

@Before
	public void setUp() throws Exception {
		//mybatis配置文件
		String resource = "SqlMapConfig.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		//使用SqlSessionFactoryBuilder创建sessionFactory
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	}
	@Test
	public void testFindUserById() throws Exception {
		//获取session
		SqlSession session = sqlSessionFactory.openSession();
		//获取mapper接口的代理对象
		UserMapper userMapper = session.getMapper(UserMapper.class);
		//调用代理对象方法
		User user = userMapper.findUserById(1);
		System.out.println(user);
		//关闭session
		session.close();
		
	}
}

5 SqlMapConfig.xml配置文件

5.1 配置内容

SqlMapConfig.xml中配置的内容和顺序如下:

properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
       transactionManager(事务管理)
       dataSource(数据源)
mappers(映射器)

5.2 properties标签

SqlMapConfig.xml可以引用java属性文件中的配置信息。

1、在classpath下定义db.properties文件,

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root

2、在SqlMapConfig.xml文件中,引用db.properties中的属性,具体如下:

   <properties resource="db.properties"/>
	<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>

properties标签除了可以使用resource属性,引用properties文件中的属性。还可以在properties标签内定义property子标签来定义属性和属性值,具体如下:

<properties>
<property name="driver" value="com.mysql.jdbc.Driver"/>
</properties>

注意: MyBatis 将按照下面的顺序来加载属性:
1、读取properties 元素体内定义的属性。
2、读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。

5.3 typeAlias标签

5.3.1 默认支持别名

别名 映射的类型

_byte 	byte 
_long 	long 
_short 	short 
_int 	int 
_integer 	int 
_double 	double 
_float 	float 
_boolean 	boolean 
string 	String 
byte 	Byte 
long 	Long 
short 	Short 
int 	Integer 
integer 	Integer 
double 	Double 
float 	Float 
boolean 	Boolean 
date 	Date 
decimal 	BigDecimal 
bigdecimal 	BigDecimal 
map	Map

5.3.2 自定义别名

在SqlMapConfig.xml中进行如下配置:

<typeAliases>
	<!-- 单个别名定义 -->
	<typeAlias alias="user" type="com.kkb.mybatis.po.User"/>
	<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
	<package name="com.kkb.mybatis.po"/>
</typeAliases>

5.4 mappers标签

5.4.1

使用相对于类路径的资源

<mapper resource="sqlmap/User.xml" />

5.4.2

使用mapper接口类路径,加载映射文件。

<mapper class="com.kkb.mybatis.mapper.UserMapper"/>

注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

5.4.3

注册指定包下的所有mapper接口,来加载映射文件。

<package name="com.kkb.mybatis.mapper"/>

注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值