文章目录
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();
}
}
}
缺陷:
- 代码比较多,开发效率低
- 需要关注 Connection ,Statement, ResultSet 对象创建和销毁
- 对 ResultSet 查询的结果,需要自己封装为 List
- 重复的代码比较多些
- 业务代码和数据库的操作混在一起
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 > #{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 > #{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 映射文件名称相同,且在同一个目录中。