MyBatis两种开发方式
使用MyBatis开发Dao,通常有两种方式,即原始Dao开发方式和Mapper接口动态代理开发方式。推荐使用第二种。
MyBatis核心API说明:
(1)SqlSession的使用范围
SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。
SqlSession通过SqlSessionFactory创建。
SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。
(2)SqlSessionFactoryBuilder
SqlSessionFactoryBuilder用于创建SqlSessionFactory,SqlSessionFactory一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory创建的。所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。
(3)SqlSessionFactory
SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory
(4)SqlSession
SqlSession是一个面向用户的接口,sqlSession中定义了数据库操作方法。
每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。
打开一个 SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。如下:
SqlSession session = sqlSessionFactory.openSession();
try {
// do work
} finally {
session.close();
}
1.1 MyBatis工具类的封装
为了方便使用SqlSession对象,需要封装工具类MyBatisUtils.java
package com.qf.utils;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtils {
public static SqlSessionFactory factory;
static{
try {
//0获取流
InputStream is=Resources.getResourceAsStream("SqlMapConfig.xml");
//1FactoryBuilder
factory=new SqlSessionFactoryBuilder().build(is);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static SqlSession openSession(){
return factory.openSession();
}
}
1.2 原始Dao方式
原始Dao开发方法需要程序员编写Dao接口和Dao实现类。
实现功能:
使用MyBatis开发DAO实现以下的功能:
(1)根据用户id查询一个用户信息
(2)根据用户名称模糊查询用户信息列表
(3)添加用户信息
第一步:编写映射文件
<?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="test">
<!-- 根据id查询用户 -->
<select id="queryUserById" parameterType="int"
resultType="cn.qf.MyBatis.pojo.User">
select * from user where id = #{id}
</select>
<!-- 根据username模糊查询用户 -->
<select id="queryUserByUsername" parameterType="string"
resultType="cn.qf.MyBatis.pojo.User">
select * from user where username like '%${value}%'
</select>
<!-- 保存用户 -->
<insert id="saveUser" parameterType="cn.qf.MyBatis.pojo.User">
<selectKey keyProperty="id" keyColumn="id" order="AFTER"
resultType="int">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>
</mapper>
第二步:创建DAO接口
public interface UserDao {
/**
* 根据id查询用户
*
* @param id
* @return
*/
User queryUserById(int id);
/**
* 根据用户名模糊查询用户
*
* @param username
* @return
*/
List<User> queryUserByUsername(String username);
/**
* 保存用户
*
* @param user
*/
void saveUser(User user);
}
第三步:Dao实现类
public class UserDaoImpl implements UserDao {
@Override
public User queryUserById(int id) {
// 创建SqlSession
SqlSession sqlSession = MyBatisUtils.openSession();
// 执行查询逻辑
User user = sqlSession.selectOne("queryUserById", id);
// 释放资源
sqlSession.close();
return user;
}
@Override
public List<User> queryUserByUsername(String username) {
// 创建SqlSession
SqlSession sqlSession = MyBatisUtils.openSession();
// 执行查询逻辑
List<User> list = sqlSession.selectList("queryUserByUsername", username);
// 释放资源
sqlSession.close();
return list;
}
@Override
public void saveUser(User user) {
// 创建SqlSession
SqlSession sqlSession = MyBatisUtils.openSession();
// 执行保存逻辑
sqlSession.insert("saveUser", user);
// 提交事务
sqlSession.commit();
// 释放资源
sqlSession.close();
}
}
第四步:测试
代码略
1.3 Mapper接口动态代理方式(重点)
Mapper接口动态代理方式(重点)Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由MyBatis框 架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
MyBatis运行时 会使用JDK(有接口)动态代理为DAO生成proxy对象 代理对象会拦截接口方法,转而执行MapperStatement所代表的sql 然后将sql返回
Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。
开发规范:
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由MyBatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper接口开发需要遵循以下规范:
1、Mapper.xml文件中的namespace与mapper接口的类路径相同。
2、Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同(注意:mapper.xml中parameterType可不写,如果不写则由Mapper接口中的方法参数类型决定)
4、Mapper接口方法的返回值类型和mapper.xml中定义的每个sql的resultType(输出参数类型)的类型相同
第一步:编写映射文件
在com.qf.mapper包中添加UserMapper.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 -->
<!-- 还有一个很重要的作用,使用动态代理开发DAO,1. namespace必须和Mapper接口类路径一致 -->
<mapper namespace="com.qf.mapper.UserMapper">
<!-- 根据用户id查询用户 -->
<!-- 2. id必须和Mapper接口方法名一致 -->
<!-- 3. parameterType必须和接口方法参数类型一致 -->
<!-- 4. resultType必须和接口方法返回值类型一致 -->
<select id="queryUserById" parameterType="int"
resultType="cn.qf.MyBatis.pojo.User">
select * from user where id = #{id}
</select>
<!-- 根据用户名查询用户 -->
<select id="queryUserByUsername" parameterType="string"
resultType="cn.qf.MyBatis.pojo.User">
select * from user where username like '%${value}%'
</select>
<!-- 保存用户 -->
<insert id="saveUser" parameterType="com.qf.pojo.User">
<selectKey keyProperty="id" keyColumn="id" order="AFTER"
resultType="int">
select last_insert_id()
</selectKey>
insert into user(username,birthday,sex,address) values
(#{username},#{birthday},#{sex},#{address});
</insert>
</mapper>
第二步: 创建DAO接口
在com.qf.mapper包中添加UserMapper.java接口
public interface UserMapper {
/**
* 根据id查询
*
* @param id
* @return
*/
User queryUserById(int id);
/**
* 根据用户名查询用户
*
* @param username
* @return
*/
List<User> queryUserByUsername(String username);
/**
* 保存用户
*
* @param user
*/
void saveUser(User user);
}
第三步: 加载映射文件
<mappers>
<mapper resource=*"com.qf.mapper/UserMapper.xml"* />
</mappers>
第四步:测试
@Test
public void testQueryUserById() {
// 获取sqlSession
SqlSession sqlSession = MyBatisUtils.openSession();
// 从sqlSession中获取Mapper接口的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 执行查询方法
User user = userMapper.queryUserById(1);
System.out.println(user);
// 和spring整合后由spring管理
sqlSession.close();
}
@Test
public void testQueryUserByUsername() {
// 获取sqlSession
SqlSession sqlSession = MyBatisUtils.openSession();
// 从sqlSession中获取Mapper接口的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 执行查询方法
List<User> list = userMapper.queryUserByUsername("张");
for (User user : list) {
System.out.println(user);
}
// 和spring整合后由spring管理
sqlSession.close();
}
@Test
public void testSaveUser() {
// 获取sqlSession
SqlSession sqlSession = MyBatisUtils.openSession();
// 从sqlSession中获取Mapper接口的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 创建保存对象
User user = new User();
user.setUsername("李小璐");
user.setBirthday(new Date());
user.setSex("1");
user.setAddress("上海");
// 执行查询方法
userMapper.saveUser(user);
System.out.println(user);
// 和spring整合后由spring管理
sqlSession.commit();
sqlSession.close();
}
总结:
selectOne和selectList
动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。
namespace
MyBatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,输入参数可以使用pojo包装对象或map对象,保证dao的通用性。
MyBatis核心配置文件
MyBatis的核心配置mybatis-config.xml中包含内容顺序如下:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
2.1 properties(属性)
自定义db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/MyBatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
mybatis-config.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>
<!-- 是用resource属性加载外部配置文件 -->
<properties resource="db.properties">
<!-- 在properties内部用property定义属性 -->
<!-- 如果外部配置文件有该属性,则内部定义属性被外部属性覆盖 -->
<property name="jdbc.username" value="root" />
<property name="jdbc.password" value="root" />
</properties>
<!-- 和spring整合后 environments配置将废除 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理 -->
<transactionManager type="JDBC" />
<!-- 数据库连接池 -->
<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>
MyBatis 将按照下面的顺序来加载属性:
(1)在 properties 元素体内定义的属性首先被读取。
(2)然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性
2.2 typeAliases(类型别名)
MyBatis支持的别名
别名 映射的类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
map Map
自定义别名
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="cn.qf.MyBatis.pojo.User" />
<!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
<package name="com.qf.pojo" />
<package name="其它包" />
</typeAliases>
2在这里插入代码片
.3 mappers(映射器)
Mapper配置的几种方法:
1. <mapper resource=" " />
使用相对于类路径的资源(现在的使用方式)
如:<mapper resource="sqlmap/User.xml" />
2. <mapper class=" " />
使用mapper接口类路径
如:<mapper class="com.qf.mapper.UserMapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
3. <package name=""/>
注册指定包下的所有mapper接口
如:<package name="com.qf.mapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
把java目录中配置也编译程序中:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<!-- 是否替换资源中的属性-->
<filtering>false</filtering>
</resource>
</resources>
</build>