mybatis 利用DAO 与利用 mapper代理 进行开发
mybatis 利用DAO开发的一般步骤
思路:程序员需要写dao接口和dao实现类。
需要向dao实现类中注入SqlSessionFactory,在方法体内通过SqlSessionFactory创建SqlSession
- 配置SqlMapConfig 与 User.xml
- 定义操作接口及其实现类
- 外部调用
对user表进行操作的接口
public interface UserOperation {
User queryUserById(int id);
List<User> queryUserByName(String name);
void insertUser();
void deleteUser();
void modifyUser();
}
接口的实现类
public class UserOperatorImpl implements UserOperation {
//需要持有一个sqlSessionFactory,以用来方便在每一个方法内产生sqlSession
private SqlSessionFactory sqlSessionFactory;
public UserOperatorImpl(SqlSessionFactory sqlSessionFactory){
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User queryUserById(int id) {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("queryUserById",id);
sqlSession.close();
return user;
}
@Override
public List<User> queryUserByName(String name) {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> users = sqlSession.selectList("queryUserByName", "王五");
sqlSession.close();
return users;
}
}
外部调用
public class MybatisDaoTest {
private static SqlSessionFactory sqlSessionFactory = null;
// 单例模式管理sqlSessionFactory,双重检锁法
public static SqlSessionFactory getSqlSessionFactory() {
if (sqlSessionFactory == null) {
synchronized (MybatisDaoTest.class) {
if (sqlSessionFactory == null) {
try {
String resource = "SqlmapConfig.xml";
// 得到配置文件流
InputStream inputStream = null;
inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
return sqlSessionFactory;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return sqlSessionFactory;
}
@Test
public void queryUserById() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
UserOperation userOperation = new UserOperatorImpl(sqlSessionFactory);
User user = userOperation.queryUserById(1);
System.out.println(user.getUsername());
}
@Test
public void queryUserByName() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
UserOperation userOperation = new UserOperatorImpl(sqlSessionFactory);
List<User> users = userOperation.queryUserByName("王五");
for (int i = 0; i < users.size(); i++){
System.out.println(users.get(i).getUsername());
}
}
}
那么从上面代码看,原生的DAO的开发方式有什么缺点呢
- dao接口实现类UserOperatorImpl, 其各个实现方法中存在大量模板方法,(比如获取sqlSession,关闭sqlSession),设想能否将这些代码提取出来,大大减轻程序员的工作量。
- 调用sqlsession方法时将statement的id(即SQL语句的唯一标识)硬编码了,比如selectOne方法中的第一个参数(”test.queryUserById”)硬编码,
- 调用sqlsession方法时传入的变量,比如selectOne方法中的参数,第一个为sql的id,第二个参数为Object 类型,由于sqlsession方法使用泛型,即使变量类型传入错误(比如 int 值写成 String值),在编译阶段也不报错,不利于程序员开发。
使用mapper代理进行开发
程序员只需要使用mapper接口,并不需要接口的具体实现就可以实现对数据库表的增删查改
当程序员遵循一定的开发规范,则mybatis可以自动生成mapper接口实现类代理对象,将配置好的mapper.xml文件加载到SqlMapConfig中即可
开发规范如下
1. 在mapper.xml中namespace等于mapper接口地址,即接口类的reference
// mapper中的配置
<mapper namespace="com.dustin.mapper.UserMapper">
<!--通过id 查询用户信息-->
<select id="queryUserById" parameterType="int" resultType="com.dustin.dao.User">
select * from user where id = #{id}
</select>
<select id="queryUserByName" parameterType="java.lang.String" resultType="com.dustin.dao.User">
select * from User where username like '%${value}%'
</select>
</mapper>
// UserMapper 中的方法
public interface UserMapper {
User queryUserById(int id);
List<User> queryUserByName(String name);
}
- id 要等于接口类UserMapper 中的方法名 即 queryUserById 就是接口类中的一个方法
- parameterType 要等于接口类中方法的参数类型
- resultType 要等于接口类中的方法的返回类型
如何调用?
// 获取一个sqlSession
SqlSession sqlSession = getSqlSessionFactory().openSession();
// 生成一个mapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.queryUserById(1);
疑惑
1. 传入的参数类型是否只能是一个?
yes,接口只有一个参数,但是可以使用包装类型的pojo满足不同的业务方法的需求
2. 返回值是单个对象还是List是怎样判断的?内部是如何知道是使用selectOne 还是selectList的?
其实是动态代理+反射, 通过看定义的方法返回的是单个对象还是一个List来判定到底是使用selectOne 还是selectList
说明: 本文大部分内容都是跟随者传播智课的教学视频学习而来,可以看做是翻译文章,只是自己吸收之后又书写一遍,加深自己的知识理解。