码迷,mamicode.com
首页 > 其他好文 > 详细

Mybatis系列一

时间:2021-04-22 16:24:31      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:http   写法   connect   回滚   javascrip   java语言   路径   ado   build   

MyBatis简介及应用

JDBC简介

JDBC是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,也是我们用来访问数据库的核心代码。而Mybatis作为一款优秀的持久层框架,其本质也是对JDBC封装。

JDBC基础代码以及问题

下面展示一段非常常见的JDBC代码:

// 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
// 通过驱动管理类获取数据库链接
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, "tom");
// 向数据库发出sql执?查询,查询出结果集
resultSet = preparedStatement.executeQuery();
// 遍历查询结果集
while (resultSet.next()) {
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
// 封装User
user.setId(id);
user.setUsername(username);
}

可以很清晰的看到JDBC代码的使用步骤非常清晰:

  1. 加载数据库驱动
  2. 获取数据库链接
  3. 定义sql语句
  4. 获取预处理
  5. 设置参数
  6. 查询出结果集
  7. 遍历查询结果集,封装结果

于此同时我们也可以看到原始JDBC开发过程中存在的一些问题:

  1. 每次使用JDBC时都会创建一个新的连接,并且在使用完成时释放掉。这样频繁的创建释放数据库连接会造成系统资源的浪费,从而影响到系统性能。
  2. 直接在java代码中定义sql,导致代码维护困难,sql改变涉及到代码的修改。
  3. 对结果集的解析同样存在硬编码问题。

JDBC问题的解决思路

  1. 使用数据库连接池初始化连接资源
  2. 将sql语句抽取到xml配置?件中
  3. 使?反射、内省等底层技术,?动将实体与表进?属性与字段的?动映射

看完这些问题我们再来看下mybatis这个持久层框架是怎么解决这些问题的。

Mybatis相关概念

Mybatis简介

MyBatis是?款优秀的基于ORM的半?动轻量级持久层框架,它?持定制化SQL、存储过程以及?级映
射。 MyBatis避免了?乎所有的JDBC代码和?动设置参数以及获取结果集。 MyBatis可以使?简单的
XML或注解来配置和映射原?类型、接?和Java的POJO (Plain Old Java Objects,普通?式Java对 象)
为数据库中的记录。
注:ORM全称Object/Relation Mapping:表示对象-关系映射的缩写。简单的来说就是将实体类与表对应起来。

MyBatis优势

Mybatis是?个半?动化的持久层框架,对开发?员开说,核?sql还是需要??进?优化, sql和java编码进?分离,功能边界清晰,?个专注业务,?个专注数据。

mybatis基本应用

快速入门

首先我们看下Mybatis的开发步骤:

  1. 在pom文件中添加Mybatis的坐标
<!--mybatis坐标-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!--mysql驱动坐标-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
<scope>runtime</scope>
</dependency>
  1. 编写与数据表相对应的实体类,这里创建的是User类
public class User {
   private int id;
   private String username;
   private String password;
   //省略get个set?法
}
  1. 编写映射?件UserMapper.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">
<mapper namespace="userMapper">
  <select id="findAll" resultType="com.lagou.domain.User">
  	select * from User
  </select>
</mapper>
  1. 编写核??件SqlMapConfig.xml,这里主要配置了两个东西,分别是数据库连接的相关参数和需要扫描的mapper
<!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:///test"/>
   			<property name="username" value="root"/>
   			<property name="password" value="root"/>
   		</dataSource>
   	</environment>
   </environments>
   <mappers>
   	<mapper resource="com/lagou/mapper/UserMapper.xml"/>
   </mappers>
</configuration>
  1. 最后我们编写一个简单的测试类,看看mybatis是如何使用的。
//加载核?配置?件
InputStream resourceAsStream =
Resources.getResourceAsStream("SqlMapConfig.xml");
//获得sqlSession??对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);	
//获得sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//执?sql语句
List<User> userList = sqlSession.selectList("userMapper.findAll");
//打印结果
System.out.println(userList);
//释放资源
sqlSession.close();

以上就是mybatis的一个简单入门案例,接下我们来对入门案例的代码进行分析。
技术图片
首先,我们看下核心配置文件SqlMapConfig.xml中的数据库环境配置。其中环境配置使用的是< environments >标签进行包裹,里面可以包裹多个< environment >标签,每一个< environment >标签代表一个环境变量的配置。< environments >中的default属性指定默认的环境变量名称。< environment >标签中的id用来指定当前环境的名称。< transactionManager >标签代表事务管理器,其中的type类型用来指定事务的管理类型。< dataSource >用来配置数据源,其中的type类型用来指定当前数据源类型。

接下来,我们来看下< environments >中各个标签的可选属性:

  1. 事务管理器(transactionManager)类型有两种:

    JDBC:这个配置就是直接使用了JDBC的提交和回滚设置,它依赖于从 数据源得到的连接来管理事务作?域。

    MANAGED:这个配置?乎没做什么。它从来不提交或回滚?个连接,?是让容器来管理事务的整个?命周期(?如 JEE 应?服务器的上下?)。 默认情况下它会关闭连接。

  2. 数据源类型有三种:

    UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。

    POOLED:这种数据源的实现利?“池”的概念将 JDBC 连接对象组织起来。

    JNDI:这个数据源的实现是为了能在如 EJB 或应?服务器这类容器中使?,容器可以集中或在外部配置数据源,然后放置?个 JNDI 上下?的引?。

再然后,我们来看下mapper标签:标签的作?是加载映射的,加载?式有4种。

  1. 使用相对于类路径的资源引?,例如:
	< mapper resource="org/mybatis/builder/UserMapper.xml" />
  1. 使?完全限定资源定位符(URL),例如:
  < mapper url="file:///var/mappers/UserMapper.xml"/>
  1. 使?映射器接?实现类的完全限定类名,例如:
	< mapper class="org.mybatis.builder.UserMapper"/>
  1. 将包内的映射器接?实现全部注册为映射器,例如:
	< package name="org.mybatis.builder"/>

注意:第四种是我们最常用的一种类型。

最后,我们来看下SqlMapConfig.xml中的一些其他常用标签。

  1. properties标签:使用该标签加载额外配置的properties文件。
    例:
< properties resource="jdbc.properties"></ properties>
  1. typeAliases标签:使用该标签为其他实体类起一个别名
    例:
< typeAliases> 
	< typeAliase type="com.xh.domain.User" alias="user"> </ typeAliase>
< /typeAliases>

SqlMapConfig.xml这个核心配置文件的分析,我们目前已经基本分析完成了。接下来,我们来分析一下mybatis的映射配置文件。
技术图片
就如上图所示,映射配置文件主要有5个重要的标签,它们分别是:

  1. mapper标签
    根标签,标签内包裹着具体的sql操作。主要属性是namespace,该属性会和下面语句的id一起组成唯一标识。
  2. select标签
    查询标签,内部包裹查询类sql语句。
  3. inser标签
    插入标签,内部包裹插入类sql语句。
  4. update标签
    修改标签,内部包裹修改类sql语句。
  5. delete标签
    删除标签,内部包裹删除类sql语句。

最后我们看下测试类的执行相关代码。
技术图片
可以看到mybatis的调用相对来说还是比较简单的,首先会将核心配置文件SqlMapConfig.xml读取为输入流。接着将输入流传入build方法中进行解析并创建SqlSessionFactory这个工厂类。再接着由SqlSessionFactory这个工厂类生产SqlSession。然后将要执行的方法所在的mapper.xml文件的命名空间加上具体执行方法的id传入并执行得到结果集。最后关闭SqlSession释放资源。

接下来,我们来看下mybatis的Dao层实现。

Mybatis的Dao层

首先,我们来看下传统开发方式下的Dao层开发。这里我们依旧使用User这个实体类进行编写。

  1. 编写UserDao接口
public interface UserDao {
	List<User> findAll() throws IOException;
 }
  1. 编写UserDaoImpl实现
public class UserDaoImpl implements UserDao {
    public List<User> findAll() throws IOException {
	InputStream resourceAsStream =
	Resources.getResourceAsStream("SqlMapConfig.xml");
	SqlSessionFactory sqlSessionFactory = new
	SqlSessionFactoryBuilder().build(resourceAsStream);
	SqlSession sqlSession = sqlSessionFactory.openSession();
	List<User> userList = sqlSession.selectList("userMapper.findAll");
	sqlSession.close();
	return userList;
}
}
  1. 编写一个测试类,看看这种方式是如何调用的
@Test
public void testTraditionDao() throws IOException {
	UserDao userDao = new UserDaoImpl();
    List<User> all = userDao.findAll();
    System.out.println(all);
}

这里传统开发方式下的Dao层开发其实与入门案例基本一致,只是一个简单的封装。这里就不在多解释了。

接下来,我们来看下代理开发?式,这也是一般开发所使用的开发形式。Mapper 接?开发?法只需要程序员编写Mapper 接?(相当于Dao 接?),由Mybatis 框架根据接?
定义创建接?的动态代理对象,代理对象的?法体同上边Dao接?实现类?法。

Mapper 接?开发需要遵循以下规范:

  1. Mapper.xml?件中的namespace与mapper接?的全限定名相同。
  2. Mapper接??法名和Mapper.xml中定义的每个statement的id相同。
  3. Mapper接??法的输?参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
  4. Mapper接??法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

让我们来看一个简单的代码片段作为例子

 @Mapper
 public interface userMapper{
 	List<User> findAll() throws IOException;
  }
<mapper namespace="userMapper">
	<select id="findAll" resultType="com.lagou.domain.User">
		select * from User
	</select>
</mapper>

技术图片
这里可以很明显的看到这两段代码所体现的Mapper 接?开发需要遵循的规范。

最后,让我们看下采用代理方式的测试方法该如何写。

@Test
public void testProxyDao() throws IOException {
 	InputStream resourceAsStream =
		Resources.getResourceAsStream("SqlMapConfig.xml");
	SqlSessionFactory sqlSessionFactory = new
	SqlSessionFactoryBuilder().build(resourceAsStream);
 	SqlSession sqlSession = sqlSessionFactory.openSession();
 	//获得MyBatis框架?成的UserMapper接?的实现类
 	UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 	User user = userMapper.findById(1);
 	System.out.println(user);
 	sqlSession.close();
}

这里相比传统模式最大的区别就是获得SqlSession之后。传统方法中直接使用SqlSession调用执行。而使用代理方法是由SqlSession生成UserMapper这个接口的代理类,然后直接调用接口方法。

Mybatis的配置文件

mybatis的配置文件主要有两类,一类是核心配置文件SqlMapConfig.xml这个在入门案例时已经讲解的较为清楚了,这里就不在叙述了。另一类就是映射配置?件mapper.xml,这里我们将简述一些映射配置?件mapper.xml的常用标签和操作。

首先,我们来了解一下动态sql。在实际工作中我们常常会碰到一些业务逻辑复杂的情况,这个时候我们就不能简单地使用sql语句进行直接查询,而需要根据复杂的业务逻辑对我们的 SQL进行动态地变化。Mybatis的动态SQL功能正是为了解决这种问题, 其通过 if, choose, when, otherwise, trim, where, set, foreach标签,方便我们将SQL语句进行灵活的组合。

  1. < where>< if></ if></ were>标签
<select id="findByCondition" parameterType="user" resultType="user">
	select * from User
	<where>
		<if test="id!=0">
			and id=#{id}
		</if>
		<if test="username!=null">
			and username=#{username}
		</if>
	</where>
</select>

这里where标签的作用是为sql语句拼接上一个 where 并判断第一个条件是否存在and,若是存在就删去and。if标签进行条件判断,若符合则动态拼接上< if>标签内包裹的语句。

  1. < foreach></ foreach>标签
<select id="findByIds" parameterType="list" resultType="user">
  select * from User
  <where>
  	<foreach collection="list" open="id in(" close=")" item="id" separator=",">
  		#{id}
  	</foreach>
  </where>
</select>

这里< foreach>标签的作用是将传来的数组,集合参数进行循环,并将每个循环出来的值拼接到sql中。接下来,我们看下< foreach>标签的各个属性。
?collection:代表要遍历的集合元素,注意编写时不要写#{}
?open:代表语句的开始部分
?close:代表结束部分
?item:代表遍历集合的每个元素,?成的变量名
?sperator:代表分隔符

  1. < sql></ sql> < include></ include>标签
<!--抽取sql?段简化编写-->
<sql id="selectUser" select * from User</sql>
<select id="findById" parameterType="int" resultType="user">
<include refid="selectUser"></include> where id=#{id}
</select>

这里的< sql>标签可将重复的 sql 提取出来,使?时?< include>标签引?,最终达到 sql 重用的目的。

Mybatis的复杂映射

在日常的业务过程中,我们经常会遇到使用多表查询的情况,我们需要在一次sql查询中查询出多个实体对象的情况,这时候就需要用到mybatis的复杂映射。我们一般遇到的复杂映射主要有三种情况,一种是一对一,一种是一对多,还有一种就是多对多。

首先,我们先来看下一对一的情况。我们来看这么一种业务场景,我们需要查询一条订单的信息,并且同时查询这个订单所属的用户信息。这就是一个典型的多对多的场景,一个订单对应一个用户。我们这里用代码来看下一对一是如何实现的。

  1. 创建订单和用户的实体
public class Order {
 private int id;
 private Date ordertime;
 private double total;
 //代表当前订单从属于哪?个客户
 private User user;
}

public class User {
 private int id;
 private String username;
 private String password;
 private Date birthday; 
 }

这里需要在Order的实体类中增加一个参数User用于接收该订单所对应的用户。

  1. 创建OrderMapper接?
public interface OrderMapper {
	List<Order> findAll();
}
  1. 配置OrderMapper.xml
<resultMap id="orderMap" type="com.lagou.domain.Order">
  <result property="id" column="id"></result>
  <result property="ordertime" column="ordertime"></result>
  <result property="total" column="total"></result>
  <association property="user" javaType="com.lagou.domain.User">
  	<result column="uid" property="id"></result>
  	<result column="username" property="username"></result>
  	<result column="password" property="password"></result>
  	<result column="birthday" property="birthday"></result>
  </association>
</resultMap>

这里我们使用association标签来对应Order实体类中的User实体类参数。

接下来我们来看下一对多的情况。这里的业务场景可以借鉴之前订单和用户的关系。之前对于订单来说每个订单都对应以个用户。现在我们反过来,对于一个用户来说是可以拥有多个订单的。我们这里用代码来看下一对多是如何实现的。

  1. 创建实体类
public class Order {
	private int id;
	private Date ordertime;
	private double total;
}

public class User {
	private int id;
	private String username;
	private String password;
	private Date birthday;
	//代表当前?户具备哪些订单
	private List<Order> orderList; 
}

这里和之前相反的是在User实体类中定义一个Order实体类的集合用于接收该用户的订单信息。

  1. 创建UserMapper接?
public interface UserMapper {
    List<User> findAll();
}
  1. 配置UserMapper.xml
<resultMap id="userMap" type="com.lagou.domain.User">
 <result column="id" property="id"></result>
 <result column="username" property="username"></result>
 <result column="password" property="password"></result>
 <result column="birthday" property="birthday"></result>
 <collection property="orderList" ofType="com.lagou.domain.Order">
 	<result column="oid" property="id"></result>
 	<result column="ordertime" property="ordertime"></result>
 	<result column="total" property="total"></result>
 </collection>
</resultMap>

这里我们使用collection 标签来对应User实体类中的Order集合。

最后,我们来看下多对多的情况。对于多对多我们可以想象一个用户和角色的业务场景。一个用户可能有多个角色,一个角色可能有多个用户拥有。其实对于mybatis而言,多对多的写法其实就是一对多写法,是一对多的应用。与多对多的不同主要在于表关系与sql语句。这里我们简单看下代码实现,其实与一对多写法基本无区别。

  1. 创建实体类
public class User {
	private int id;
	private String username;
	private String password;
    private Date birthday;
    //代表当前?户具备哪些??
	private List<Role> roleList; 
}
public class Role {
	private int id;
	private String rolename; 
}

这里和之前相反的是在User实体类中定义一个Role实体类的集合用于接收该用户的角色信息。

  1. 创建UserMapper接?
public interface UserMapper {
   List<User> findAllUserAndRole();
}
  1. 配置UserMapper.xml
<resultMap id="userRoleMap" type="com.lagou.domain.User">
 <result column="id" property="id"></result>
 <result column="username" property="username"></result>
 <result column="password" property="password"></result>
 <result column="birthday" property="birthday"></result>
 <collection property="roleList" ofType="com.lagou.domain.Role">
 	<result column="rid" property="id"></result>
 	<result column="rolename" property="rolename"></result>
 </collection>
</resultM

这里我们可以很清晰的看到多对多的映射写法与一对一基本一致。

Mybatis系列一

标签:http   写法   connect   回滚   javascrip   java语言   路径   ado   build   

原文地址:https://www.cnblogs.com/xjscf/p/14687871.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!