Java框架 第一部分 MyBatis


1 框架概述

三层框架

三层框架
界面层
业务逻辑层
数据访问层

好处

  • 结构清晰、耦合度低, 各层分工明确
  • 可维护性高,可扩展性高
  • 有利于标准化
  • 开发人员可以只关注整个结构中的其中某一层的功能实现
  • 有利于各层逻辑的复用

JDBC编程回顾

public void findStudent() {
    
    
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
    
    
            //注册 mysql 驱动
            Class.forName("com.mysql.jdbc.Driver");
            //连接数据的基本信息 url ,username,password
            String url = "jdbc:mysql://localhost:3306/springdb";
            String username = "root";
            String password = "123456";
            //创建连接对象
            conn = DriverManager.getConnection(url, username, password);
            //保存查询结果
            List<Student> stuList = new ArrayList<>();
            //创建 Statement, 用来执行 sql 语句
            stmt = conn.createStatement();
            //执行查询,创建记录集,
            rs = stmt.executeQuery("select * from student");
            while (rs.next()) {
    
    
                Student stu = new Student();
                stu.setId(rs.getInt("id"));
                stu.setName(rs.getString("name"));
                stu.setAge(rs.getInt("age"));
                //从数据库取出数据转为 Student 对象,封装到 List 集合
                stuList.add(stu);
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                //关闭资源
                if (rs != null) ;
                {
    
    
                    rs.close();
                }
                if (stmt != null) {
    
    
                    stmt.close();
                }
                if (conn != null) {
    
    
                    conn.close();
                }
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }
        }
    }

缺陷:

  1. 代码比较多,开发效率低
  2. 需要关注 Connection ,Statement, ResultSet 对象创建和销毁
  3. 对 ResultSet 查询的结果,需要自己封装为 List
  4. 重复的代码比较多些
  5. 业务代码和数据库的操作混在一起

MyBatis框架

MyBatis 本是 apache 的一个开源项目 iBatis, 2010 年这个项目由 apache software foundation 迁移到了 google code,并且改名为 MyBatis 。2013 年 11 月迁移到 Github。

iBATIS 一词来源于“internet”和“abatis”的组合,是一个基于 Java 的持久层框架。iBATIS 提供的持久层框架包括 SQL Maps 和 Data Access Objects(DAOs)

1) SQL Maps :sql映射
可以把数据库表中的一行数据 映射为 一个java对象。
一行数据可以看做是一个java对象。操作这个对象,就相当于操作表中的数据
2) Data Access Objects(DAOs) : 数据访问 , 对数据库执行增删改查。

MyBatis 解决的主要问题:减轻使用 JDBC 的复杂性,不用编写重复的创建 Connetion , Statement ; 不用编写关闭资源代码。直接使用 java 对象,表示结果数据。让开发者专注 SQL 的处理。

2 MyBatis入门

下载:mybatis

IDEA中创建maven工程,pom.xml中加入maven坐标,加入maven插件
编写Dao接口的Mapper映射文件
创建 MyBatis 主配置文件

3 MyBatis Dao代理

MyBatis 框架就抛开了 Dao 的实现类,直接定位到映射文件 mapper 中的相应 SQL 语句,对DB 进行操作。这种对 Dao 的实现方式称为 Mapper 的动态代理方式。Mapper 动态代理方式无需程序员实现 Dao 接口。接口是由 MyBatis 结合映射文件自动生成的动态代理实现的。

StudentDao studentDao = 
MyBatisUtil.getSqlSession().getMapper(StudentDao.class);

参数传递

Dao 接口中方法的参数只有一个简单类型(java 基本类型和 String),占位符 #{ 任意字符 },和方法的参数名无关。

当 Dao 接口方法多个参数,需要通过名称使用参数。在方法形参前面加入@Param(“自定义参数名”),mapper 文件使用#{自定义参数名}

接口方法:
List<Student> selectMultiParam(@Param("personName") String name,
 @Param("personAge") int age);
 
mapper 文件:
<select id="selectMultiParam" resultType="Student">
	select id,name,email,age from student where name=#{
    
    personName} or age =#{
    
    personAge}
</select>

使用 java 对象传递参数, java 的属性值就是 sql 需要的参数值。 每一个属性就是一个参数。
语法格式:#{ property,javaType=java 中数据类型名,jdbcType=数据类型名称 }
javaType, jdbcType 的类型 MyBatis 可以检测出来,一般不需要设置。常用格式 #{ property }

参数位置从 0 开始, 引用参数语法 #{ arg 位置 } , 第一个参数是#{arg0}, 第二个是#{arg1}
注意:mybatis-3.3 版本和之前的版本使用#{0},#{1}方式, 从 mybatis3.4 开始使用#{arg0}方式。

Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数。Map 集合使用 String的 key,Object 类型的值存储参数。 mapper 文件使用# { key }引用参数值。

#和$
#:占位符,告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句, #{…}代替sql 语句的“?”。
这样做更安全,更迅速,通常也是首选做法,

$ 字符串替换,告诉 mybatis 使用 $ 包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的内容连接起来。
主要用在替换表名,列名,不同列排序等操作。

  1. #使用 ?在sql语句中做站位的, 使用PreparedStatement执行sql,效率高
  2. #能够避免sql注入,更安全。
  3. $不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低
  4. $有sql注入的风险,缺乏安全性。
  5. $:可以替换表名或者列名

输出结果

resultType

简单类型

mapper 文件:
<select id="countStudent" resultType="int">
	select count(*) from student
</select>

对象类型

<select id="selectById" resultType="com.bjpowernode.domain.Student">
	select id,name,email,age from student where id=#{studentId}
</select>

Map
sql 的查询结果作为 Map 的 key 和 value。推荐使用 Map<Object,Object>。
注意:Map 作为接口返回值,sql 语句的查询结果最多只能有一条记录。大于一条记录是错误。

接口方法:
Map<Object,Object> selectReturnMap(int id);

mapper 文件:
<select id="selectReturnMap" resultType="java.util.HashMap">
	select name,email from student where id = #{studentId}
</select>
测试方法:
@Test
public void testReturnMap(){
    
    
	Map<Object,Object> retMap = studentDao.selectReturnMap(1002);
	System.out.println("查询结果是 Map:"+retMap);
}

resultMap

resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。更灵活的把列值赋值给指定属性。常用在列名和 java 对象属性名不一样的情况。

使用方式:
1.先定义 resultMap,指定列名和属性的对应关系。
2.在中把 resultType 替换为 resultMap。

接口方法:
List<Student> selectUseResultMap(QueryParam param);

mapper 文件:
<resultMap id="studentMap" type="com.bjpowernode.domain.Student">
	<!-- 主键字段使用 id -->
	<id column="id" property="id" />
	<!--非主键字段使用 result-->
	<result column="name" property="name"/>
	<result column="email" property="email" />
	<result column="age" property="age" />
</resultMap>

<select id="selectUseResultMap" resultMap="studentMap">
	select id,name,email,age from student 
	where name=#{queryName} or age=#{queryAge}
</select>

测试方法:
@Test
public void testSelectUseResultMap(){
	QueryParam param = new QueryParam();
	param.setQueryName("李力");
	param.setQueryAge(20);
	List<Student> stuList = studentDao.selectUseResultMap(param);
	stuList.forEach( stu -> System.out.println(stu));
}

4 MyBatis动态SQL

if
对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。语法:<if test=”条件”> sql 语句的部分 </if>

符号 实体符号
< <
> >
>= >=
<= <=
mapper 文件:
<select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
	select id,name,email,age from student
	where 1=1
	<if test="name != null and name !='' ">
		and name = #{name}
	</if>
	<if test="age > 0 ">
		and age &gt; #{age}
	</if>
</select>

where
使用< where/>标签,在有查询条件时,可以自动添加上 where 子句;没有查询条件时,不会添加where 子句。需要注意的是,第一个< if/>标签中的 SQL 片断,可以不包含 and。不过,写上 and 也不错,系统会将多出的 and 去掉。但其它< if/>中 SQL 片断的 and,必须要求写上。否则 SQL 语句将拼接出错

mapper 文件:
<select id="selectStudentWhere" resultType="Student">
	select id,name,email,age from student
	<where>
	<if test="name != null and name !='' ">
		and name = #{name}
	</if>
	<if test="age > 0 ">
		and age &gt; #{age}
	</if>
	</where>
</select>

foreach
< foreach/>标签用于实现对于数组与集合的遍历。对其使用,需要注意:
➢ collection 表示要遍历的集合类型, list ,array 等。
➢ open、close、separator 为对遍历内容的 SQL 拼接。

语法:
<foreach collection="集合类型" open="开始的字符" close="结束的字符" 
		item="集合中的成员" separator="集合成员之间的分隔符">
	#{item 的值}
</foreach>
mapper 文件:
<select id="selectStudentForList2" 
resultType="Student">
	select id,name,email,age from student
	<if test="list !=null and list.size > 0 ">
		where id in
		<foreach collection="list" open="(" close=")" 
				item="stuobject" separator=",">
			#{stuobject.id}
		</foreach>
	</if>
</select>

代码片段
< sql/>标签用于定义 SQL 片断,以便其它 SQL 标签复用。而其它标签使用该 SQL 片断,需要使用< include/>子标签。该标签可以定义 SQL 语句中的任何部分,所以< include/>子标签可以放在动态 SQL的任何位置

mapper 文件:
<!--创建 sql 片段 id:片段的自定义名称--> 
<sql id="studentSql">
	select id,name,email,age from student
</sql>

<select id="selectStudentSqlFragment" resultType="Student">
	<!-- 引用 sql 片段 -->
	<include refid="studentSql"/>
	<if test="list !=null and list.size > 0 ">
		where id in
		<foreach collection="list" open="(" close=")" 
				item="stuobject" separator=",">
			#{stuobject.id}
		</foreach>
	</if>
</select>

5 MyBatis配置文件

注意点:
1 使用数据库属性配置文件

<properties resource="jdbc.properties" />

<dataSource type="POOLED">
	<!--使用 properties 文件: 语法 ${key}-->
	<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>

2 typeAliases(类型别名)

<typeAliases>
	<!--
		定义单个类型的别名
		type:类型的全限定名称
		alias:自定义别名 
	-->
<typeAlias type="fun.rtzhao.domain.Student" alias="mystudent"/>
	 <!--
		 批量定义别名,扫描整个包下的类,别名为类名(首字母大写或小写都可以)
		 name:包名 
	 -->
	<package name="fun.rtzhao.domain"/>
	<package name="...其他包"/>
</typeAliases>

 mapper.xml 文件,使用别名表示类型
<select id="selectStudents" resultType="mystudent">
	select id,name,email,age from student
</select>

3 mappers(映射器)

1)< mapper resource=" " />
使用相对于类路径的资源,从 classpath 路径查找文件
例如:< mapper resource="com/bjpowernode/dao/StudentDao.xml" />
2)< package name=""/>
指定包下的所有 Dao 接口
如:< package name="com.bjpowernode.dao"/>
注意:此种方法要求 Dao 接口名称和 mapper 映射文件名称相同,且在同一个目录中。


传送门

下一章:

猜你喜欢

转载自blog.csdn.net/RTyinying/article/details/114767073
今日推荐