最近在学SSM框架,现在来简单介绍一下,SSM里的mybatis框架。
首先来介绍一下ORM
1.ORM简介
Object Relational Mapping:对象关系映射。
简单的理解:ORM是通过使用描述对象和数据库之间的映射关系的 元数据, 将程序中的对象自动的持久化到关系型数据库中。
SSH里的hibernate和SSM里的mybatis都是ORM框架
其次来简单介绍了一下传统的jdbc,毕竟mybatis的出现就是来代替TA的
2.传统的JDBC
传统的jdbc的操作流程:
- 加载驱动
- 获取连接connection
- 获取预处理对象statement
- 设置sql(采用占位符,防止sql注入)
- 给占位符设置值
- 执行获取结果集
- 对结果集进行封装
- 释放资源
在传统的jdbc中存在了一些问题:
- 频繁的创建连接、释放资源、造成了系统资源的浪费。(数据库连接池可以解决这个问题)
- sql语句在Java代码中,造成后期维护不易
- 占位符设置值存在硬编码。where 语句里的条件不固定,造成维护不易
- 对结果集的解析封装存在硬编码
以上的问题在mybatis里都可以得到比较好的解决⬇⬇⬇
3.mybatis架构
mybatis架构是一个ORM框架,是一个基于Java的持久化框架。
mybatis会对jdbc的操作过程进行封装,使得卡法这只需要关注SQL本身,而无需花费精力去注册驱动、获取连接、设置参数、结果数据分析、释放资源等工作。可以简化jdbc开发成本
4.mybatis环境搭建
- 新建Java项目,导入jar包 mybatis-3.2.7.jar 和 junit(用来测试)
- 配置log4j.properties 打印日志
- 配置mybatis全局配置文件 mybatis.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>
<!-- 运行环境:与spring整合后就不需要了
default:运行哪个环境,里面是id -->
<environments default="mysql">
<environment id="mysql">
<!--事务管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 数据源 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
5.入门案例
1.创建一个pojo对象类
private int id;
private String username;
// getter
// setter
//toString --- 便于在控制台打印查看信息
2.映射文件 mapper.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">
<!-- namespace的作用:分割sql,也就在调用这个文件的时候来认证 -->
<mapper namespace="UserMapper">
<!-- 入门程序:根据id查询用户信息
id:唯一的(本namespace下唯一),用于标识映射文件的sql,成为statement的id
parameterType:输入参数类型;支持的类型包括java基本类型、pojo对象、hashmap
resultType:输出结果类型;指定为单挑记录的类型
#{}:占位符 注意:如果输入的参数类型是基本类型,则#{}里面可以是任意参数。或者是#{value}
-->
<select id="selectById" parameterType="int" resultType="user">
select * from user where id = #{id}
</select>
</mapper>
3.测试用例
private SqlSession sqlSession;
@Before
public void init() throws IOException {
// 初始化、加载环境、创建会工厂、获取会话
// 1.加载mybatis的运行环境 io流的方式去读取全局配置文件
InputStream is = Resources.getResourceAsStream("mybatis.xml");
// 2.创建会话工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
// 3.获取会话,要通过会话来进行操作数据库
sqlSession = sqlSessionFactory.openSession();
}
@Test
public void selectById() {
// 4.操作数据库
// 第一个参数:statement的id 具体执行的sql 写法:namespace.id(具体sql语句的id)
// 第二个参数:值
User user = sqlSession.selectOne("UserMapper.selectById",1);
System.err.println(user);
}
@After
public void after() {
// 释放资源
sqlSession.close();
}
6.会话工厂与会话
SqlSessionFactory:会话工厂。通过全局配置文件创建的,由SqlSessionFactoryBuild对象创建。
作用:创建会话
特点:会话工厂一旦创建,就会在应用程序的执行期间一直存在。我们不需要重复的来创建会话工厂,所以,应该将会话工厂的实现方式设计为单例模式
SqlSession: 会话。
作用:操作数据库的
特点:线程不安全的。应该把会话声明为局部的。
7.全局配置文件的其他配置
1.起别名(两种方式)
<!-- 起别名 -->
<typeAliases>
<!-- 方法一 -->
<!-- type:指的是要被定义别名的类的 全限定名 -->
<!-- <typeAlias type="com.cbb.pojo.User" alias="user"/> -->
<!-- 方法二 -->
<!-- 批量起别名
会扫描配置的包下的所有的类,然后,批量的起别名。别名为类型(首字母大写或者小写都可以) -->
<package name="com.cbb.pojo"/>
</typeAliases>
2.加载外部资源
资源文件 db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
全局配置文件 mybatis.xml 里面加载外部资源文件
<!-- 加载资源文件 -->
<properties resource="db.properties"></properties>
<environments default="mysql">
<environment id="mysql">
<!--事务管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 数据源 -->
<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>
8.动态代理实现
传统的dao开发方法:dao接口、 daoImpl实现
与之相比
动态代理的实现:mapper接口、映射文件mapper.xml
只需要程序员编写Mapper接口(相当于dao接口),和映射文件,由 mybatis框架根据 接口 来创建接口的动态代理 对象,来代理接口方法的实现(类似于传统dao开发方式中的实现类)
规范要求:
- mapper.xml映射文件 和 mapper接口的名字 必须一致。
- mapper.xml映射文件的 namespace 与 接口 的类全路径相同
- mapper.xml映射文件的 statement的id 与 接口的方法名相同
- mapper.xml映射文件 的参数类型parameterType 与 接口方法的 参数类型相同
- mapper.xml映射文件 的输出结果类型 与 接口方法的 返回类型相同
可以在全局配置文件里批量加载 映射文件
<!-- 加载映射文件 -->
<mappers>
<!-- 批量加载包下的映射文件 -->
<package name="com.cbb.mapper"/>
</mappers>
9.servlet与mybatis整合
与servlet整合,其实主要需要更改的地方便是serviceImpl里的代码实现,不再是通过实例化dao对象来调用方法,而是直接通过会话获取代理对象,然后来调用方法。
注意一点:如果是对数据库进行新增、修改、删除,在关闭会话之前记得调用commit方法,否则数据库里的数据不会改变
public class UserServiceImpl implements UserService{
private SqlSessionFactory factory = SqlSessionFactoryUtil.getSqlSessionFactory();//获取单例模式的会话工厂
@Override
public User selectById(int id) {
SqlSession session = factory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);//获取代理对象
User user = userMapper.selectById(id);//方法调用
session.close();//是否资源 如果是新增、修改、删除,关闭前记得要 调用 commit方法
return user;
}
}
10.Mapper.xml详解
mapper.xml - - 映射文件
1.parameterType(输入类型)
- java简单类型 int、String 占位符的形式 #{任意字符}
- pojo自定义对象 #{pojo的属性名}
- hasmap
2.resultType(输出类型)
- Java简单类型的
- pojo自定义对象
- hashmap
3.resultMap
resultType:在指定pojo对象接收映射的结果集时,需要将pojo对象,需要要将pojo对象的属性名和数据库表的字段名要一致。如果有不一致的,则查询的字段为null
解决问题不一致的方法:
方案一:给sql查询的字段 as 别名,别名与pojo的属性名一致
<!-- 方案一:给sql查询的字段 as 别名, 别名和pojo对象的属性名一致 -->
SELECT carId carId, `name` carName , userId userId from car
方案二:
使用resultMap
注意一点:如果使用resultMap来处理这种简单的 名字不一致的问题的时候,可以在resultMap里只配置这个名字不一致的字段,名字一致的可以省略掉。
<!--
type:把结果集映射到哪个对象上
<id/>:结果集的主键 唯一标识
<result/>:结果集的普通字段
column:表的字段名
property:pojo对象的属性名
column和property 在一起表示之间的映射关系
-->
<!-- 可以只设置名字不一样的字段 -->
<resultMap type="Car" id="CarMap">
<id column="carId" property="carId"/>
<result column="name" property="carName"/>
<result column="userId" property="userId"/>
</resultMap>
<!-- resultMap:对应自定义的 哪个resultMap 的id -->
<select id="selectAll" resultMap="CarMap">
select * from car;
</select>
resultMap:除了能够解决名字不一致的问题之外,还可以解决复杂的pojo问题。
<resultMap type="UserVo" id="UserVoMap">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<result column="address" property="address"/>
<!-- 一对多集合 ofType:集合的类型 -->
<collection property="car" ofType="Car">
<id column="carId" property="carId"/>
<result column="name" property="carName"/>
<result column="userId" property="userId"/>
</collection>
</resultMap>
11.动态SQL
通过mybatis提供的各种标签方法实现动态拼接sql
1.where条件的拼接,if用例
- if: 语句判断, <if test=""> 使用and进行合并
- where: 去除多余的and 或者是 or , 所以在每一个条件句之前都加一个 and
<!-- 动态sql:if用例 -->
<select id="selectIf" parameterType="map" resultType="User">
select * from user
<where>
<if test="sex!=null and sex!=''">
and sex = #{sex}
</if>
<if test="address!=null and address!=''">
and address like concat("%", #{address}, "%")
</if>
</where>
</select>
2.更新语句,set : 能去除多余的逗号(,), 所以在每个条件语句之后都加一个逗号即可
<!-- set -->
<update id="updateUser" parameterType="User">
update user
<set>
<if test="username!=null and username!=''">
username = #{username},
</if>
<if test="sex!=null and sex!=''">
sex = #{sex},
</if>
<if test="address!=null and address!=''">
address = #{address},
</if>
</set>
<where>
id = #{id}
</where>
</update>
3.foreach循环,以批量删除为例
foreach里各种属性的含义:
collection:集合的类型,可以是list(list集合) / array(数组) / map / pojo包装类中的属性名
item:循环中的当前对象
open:循环的开始
close:循环的结束
separator:分割符
<!-- foreach:批量删除
collection:集合的类型,可以是list(list集合) / array(数组) / map / pojo包装类中的属性名
item:循环中的当前对象
open:循环的开始
close:循环的结束
separator:分割符
-->
<delete id="deleteBatch" parameterType="int">
delete from user where id in
<foreach collection="list" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</delete>