MyBatis 01:入门
1.概述
三层架构
- 界面层(User Interface layer):接受用户的数据,显示请求的处理结果。---SpringMVC-----controller包 (servlet)
- 业务逻辑层(Business Logic Layer):接收表示传递过来的数据,检查数据,计算业务逻辑,调用数据访问层获取数据----Spring----service 包(XXXService类)
- 数据访问层(Data access layer):实现对数据库的增、删、改、查。将数据库的数据提交给业务层,同时将业务层处理的数据保存到数据库---MyBatis----dao包(XXXDao类)
何为框架?
整个或部分系统的可重用设计,一组抽象构件及构件实例间交互的方法;
开发者定制的应用骨架、模板;
安全的,可复用的,不断升级的软件。
何为 MyBatis?
MyBatis ,基于 java 的持久层框架,内部封装 jdbc,开发只需关注 sql 语句而不需要处理加载驱动、创建连接、创建 statement、关闭连接,资源等繁杂的过程;通过 xml 或注解两种方式将要执行的各种 sql 语句配置起来,并通过 java 对象和 sql 的动态参数进行映射生成执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。
提供sql语句--mybatis处理sql---得到List集合或java对象(表中的数据)
2.基本操作
2.1 流程
1.创建 mysql 数据库和表
2.创建 maven 工程
3.pom.xml 加入 maven 坐标;加入 maven 插件
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<!--所在的目录-->
<directory>src/main/java</directory>
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
4.建立Dao,不需要实现
5.Dao 接口 Mapper 映射文件
- dao 包中创建文件xml
- 文件名称和接口 Dao 一样
<!--
namespace:必须有值,自定义的唯一字符串
推荐使用:dao 接口的全限定名称
-->
<mapper namespace="com.fremont.dao.StudentDao">
<!--
<select>: 查询数据, 标签中必须是 select 语句
id: sql 语句的自定义名称,推荐使用 dao 接口中方法名称,
使用名称表示要执行的 sql 语句
resultType: 查询语句的返回结果数据类型,使用全限定类名
-->
<select id="selectStudents" resultType="com.fremont.domain.Student">
<!--要执行的 sql 语句-->
select id,name,email,age from student
</select>
</mapper>
6.创建MyBatis主配置文件
- src/main 下创建 resources 目录
- 创建主配置文件 mybatis.xml
<configuration>
<!--配置 mybatis 环境-->
<environments default="mysql">
<!--id:数据源的名称-->
<environment id="mysql">
<!--配置事务类型:使用 JDBC 事务(使用 Connection 的提交和回滚)-->
<transactionManager type="JDBC"/>
<!--数据源 dataSource:创建数据库 Connection 对象
type: POOLED 使用数据库的连接池
-->
<dataSource type="POOLED">
<!--连接数据库的四个要素-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<!--支持中文加上 ?useUnicode=true&characterEncoding=utf-8-->
<property name="username" value="root"/>
<property name="password" value="fremont"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--告诉 mybatis 要执行的 sql 语句的位置-->
<mapper resource="com/fremont/dao/StudentDao.xml"/>
</mappers>
</configuration>
7.测试使用
public class MyBatisTest {
@Test
public void testStart() throws IOException {
//1.mybatis 主配置文件
//目录从 target/classes 开始
String config = "mybatis.xml";
//2.读取配置文件
InputStream in = Resources.getResourceAsStream(config);
//3.创建 SqlSessionFactory 对象,目的是获取 SqlSession
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//4.获取 SqlSession,SqlSession 能执行 sql 语句
SqlSession session = factory.openSession();
//5.执行 SqlSession 的 selectList()
List<Student> list = session.selectList("com.fremont.dao.StudentDao.selectStudents");
//6.循环输出查询结果
list.forEach(s -> System.out.println(s));
//7.关闭 SqlSession,释放资源
session.close();
}
}
8.配置日志
mybatis.xml 文件加入日志配置,在控制台输出执行的 sql 语句和参数
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
2.2 CRUD
在dao的xml配置文件中配置sql语句
<mapper namespace="com.fremont.dao.StudentDao">
<!--要执行的 sql 语句-->
<select id="selectStudents" resultType="com.fremont.domain.Student">
select id,name,email,age from student
</select>
<insert id="insertStudent">
insert into student(id,name,email,age) values(#{id},#{name},#{email},#{age})
</insert>
<update id="updateStudent">
update student set age = #{age} where id=#{id}
</update>
<delete id="deleteStudent">
delete from student where id=#{studentId}
</delete>
</mapper>
2.3 对象分析
2.3.1 对象
Resources 类
- 用于读取资源文件
- 有很多方法通过加载并解析资源文件,返回不同类型的 IO 流对象
SqlSessionFactoryBuilder 类
- SqlSessionFactoryBuilder对象的build() 方法创建SqlSessionFactory工厂对象
- 创建完工厂对象后,就完成了其使命,即可被销毁
- 一般将该 SqlSessionFactoryBuilder 对象创建为局部对象
SqlSessionFactory 接口
- 重量级对象(系统开销大),线程安全,一个应用只需要一个该对象
-
创建 SqlSession使用 SqlSessionFactory 接口的 openSession()方法
- openSession(true):创建一个有自动提交功能的 SqlSession
- openSession():默认false 创建一个非自动提交功能的 SqlSession,需手动提交
SqlSession 接口
- SqlSession 接口对象用于执行持久化操作:
- selectOne() ,selectList() ,insert(),update(), delete(), commit(), rollback()
- SqlSession对应数据库会话:以SqlSession 对象的创建开始,以 SqlSession 对象的关闭结束
- SqlSession 接口对象是线程不安全,会话结束前,需要马上调用close()方法
- SqlSession 在方法内部创建,使用完毕后关闭
2.3.2 工具类
MyBatisUtil 类
public class MyBatisUtil {
//定义 SqlSessionFactory
private static SqlSessionFactory factory = null;
static {
//使用 静态块 创建一次 SqlSessionFactory
try {
String config = "mybatis.xml";
//读取配置文件
InputStream in = Resources.getResourceAsStream(config);
//创建 SqlSessionFactory 对象
factory = new SqlSessionFactoryBuilder().build(in);
} catch (Exception e) {
factory = null;
e.printStackTrace();
}
}
/* 获取 SqlSession 对象 */
public static SqlSession getSqlSession() {
SqlSession session = null;
if (factory != null) {
session = factory.openSession();
}
return session;
}
}
2.4 传统Dao开发
实现dao
public List<Student> selectStudents() {
SqlSession session = MyBatisUtil.getSqlSession();
List<Student> studentList = session.selectList("com.bjpowernode.dao.StudentDao.selectStudents");
session.close();
return studentList;
}
public int insertStudent(Student student) {
SqlSession session = MyBatisUtil.getSqlSession();
int nums = session.insert("com.bjpowernode.dao.StudentDao.insertStudent",student);
session.commit();
session.close();
return nums;
}
- 真正进行操作的是由框架通过 mapper 中的 SQL 完成的
- 所以,MyBatis 框架就抛开了 Dao 的实现类,直接定位到映射文件 mapper 中的相应 SQL 语句
- Mapper 的动态代理方式
3.MyBatis代理Dao
- mybatis的动态代理: mybatis根据 dao的方法调用,获取执行sql语句的信息
- mybatis根据dao接口,创建出一个dao接口的实现类, 并创建这个类的对象
- 完成SqlSession调用方法, 访问数据库
3.1 Dao代理实现
getMapper 获取代理对象
/**
* 使用mybatis的动态代理机制, 使用SqlSession.getMapper(dao接口)
* getMapper能获取dao接口对应的实现类对象。
*/
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
//com.sun.proxy.$Proxy2 : jdk的动态代理
System.out.println("dao=" + dao.getClass().getName());
3.2 参数
parameterType:
- mapper文件中属性,属性是可选的
- dao接口中方法的参数的数据类型
- 类型的完全限定名或别名
简单类型:
- java的基本数据类型和String
- mapper文件获取简单类型参数值,#{任意字符}占位符
- 占位符和方法的参数名无关
多个参数:
- @Param命名参数
//接口
public List<Student> selectMulitParam(@Param("myname") String name, @Param("myage") Integer age);
/*mapper文件
<select id="selectMultiParam" resultType="com.fremont.domain.Student">
select * from student where name=#{myname} or age=#{myage}
</select>
*/
- 使用java对象:传入对象,每一个属性就是一个参数
/*创建查询参数对象
vo: value object , 放一些存储数据的类。
比如 提交请求参数 name ,age ;把name ,age 传给一个service 类
vo: view object , 从servlet把数据返回给浏览器使用的类,表示显示结果的类。
pojo: 普通的有set, get方法的java类。 普通的java对象
entity(domain域): 实体类, 和数据库中的表对应的类
*/
List<Student> selectMultiObject(QueryParam queryParam);
/*mapper 文件:
完整格式:#{ 属性名,javaType=java数据类型名,jdbcType=数据类型名称 }
一般:#{ 属性名 }
<select id="selectMultiObject"resultType="com.fremont.domain.Student">
select id,name,email,age from student
where name=#{queryName} or age=#{queryAge}
</select>
*/
- 按参数位置: #{ arg 位置 i } 例如 #{ arg 0 }、#{ arg 1 }
- 使用Map:
- Map<String,Object> data 格式:
- List
selectMultiMap(Map<String,Object> map); - mapper 文件使用 # { key } 引用参数
- #占位符:使用 PrepareStatement 对象执行 sql 语句,首选
- $ 字符串替换:用 Statement 把 sql 语句和${}的内容连接起来
//替换表名,列名,不同列排序等操作
Student findByDiffField(
@Param("col") String colunName,@Param("cval") Object value);
<select id="findByField" resultType="com.xxx.domain.Student">
select * from student where ${col} = #{cval}
</select>
- #和 $区别
使用 ?在sql语句中占位的, 使用PreparedStatement执行sql,效率高
能够避免sql注入,更安全
- $不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低
- $有sql注入的风险,缺乏安全性
- $:可以替换表名或者列名
3.3 封装MyBatis结果
resultType:
- 执行 sql 得到 ResultSet 转换的类型:
- mybatis调用类的无参数构造方法,创建对象
- mybatis把ResultSet指定列值付给同名的属性,使用set方法
- 类型的完全限定名或别名
- 返回的是集合,应设置为集合包含的类型
- resultType 和 resultMap,不能同时使用
<!--简单类型/对象类型
Map:推荐使用 Map<Object,Object>
Map 作为接口返回值,sql 语句的查询结果最多只能有一条记录
Map<Object,Object> selectReturnMap(int id);
-->
<select id="selectReturnMap" resultType="java.util.HashMap">
select name,email from student where id = #{studentId}
</select>
<!--自定义类型别名:
mybatis主配置文件中定义
-->
<typeAliases>
<typeAlias type="com.fremont.domain.Student" alias="Stu"/>
<!--指定包后可以直接使用类名-->
<package name="com.fremont.domain"/>
</typeAliases>
resultMap:
- 自定义 sql 的结果和 java 对象属性的映射关系
- 常用在列名和 java 对象属性名不一样的情况
<!-- mapper 创建 resultMap
id:自定义的唯一名称,在<select>使用
type:期望转为的 java 对象的全限定名称或别名
-->
<resultMap id="studentMap" type="com.fremont.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>
<!--resultMap: resultMap 标签中的 id 属性值-->
<select id="selectUseResultMap" resultMap="studentMap">
select id,name,email,age from student where name=#{queryName} or
age=#{queryAge}
</select>
实体类属性名和列名不同:
- 使用列别名和resultType
- 使用resultMap
3.4 模糊查询
java 代码中给查询数据加上“%”:传入字符串含有%
mapper 文件 sql 语句条件位置加上“%”:like name "%" #{xxx} "%"