Mybatis学习笔记(三) 之Dao开发
使用Mybatis开发Dao,通常有两个方法,即原始Dao开发方法和Mapper接口开发方法,常用还是Mapper接口开发。
SqlSession的使用范围
public class test1 {
private static SqlSessionFactory sqlSessionFactory;
private static Reader reader;
//创建会话工厂,传入mybatis的配置文件信息
static{
try{
//得到配置文件流
reader = Resources.getResourceAsReader("Configuration.xml");
//创建会话工厂,传入mybatis的配置文件信息
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
}catch(Exception e){
e.printStackTrace();
}
}
//查询数据
public void select() {
//通过工厂得到sqlsession
SqlSession session = sqlSessionFactory.openSession();
try {
//通过SqlSession操作数据库//第一个参数:映射文件中statement的id//第二个参数:指定和映射文件所匹配的parameterType类型参数
User user = (User) session.selectOne("com.yihaomen.mybatis.model.User.selectUserByID", 1);
} finally {
session.close();
}
}
}
想要通过mabatis对数据库操作,除了要各种配置之外,最终在测试的时候,需要创建特定对象,上图示例:
1、SqlSessionFactoryBuilder
SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory生产,所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。
2、SqlSessionFactory
SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory
3、SqlSession
SqlSession是一个面向用户的接口, sqlSession中定义了数据库操作,默认使用DefaultSqlSession实现类。
SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。通过SqlSessionFactory创建SqlSession,而SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。
结论:
每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。
打开一个 SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。
//通过工厂得到sqlsession
SqlSession session = sqlSessionFactory.openSession();
try {
} finally {
session.close();
}
原始Dao开发方式
程序员需要编写DAO和DAO的实现类。需要向DAO实现类中注入SqlSessionFactory
,在方法体内通过SqlSessionFactory来创建SqlSession。
1、定义Dao接口
public interface UserDAO{ //根据本id查询用户
User findUserById(int id) throws Exception;
//添加用户
void insertUser(User user) throws Exception;
//根据id删除用户
void deleteUser(int id) throws Exception;
}
2、Dao实现类
DAO实现类
/**
* @ClassName: UserDAOImpl
* @Description: DAO实现类(注意:SqlSession是非线程安全的,故不能声明为全局的)
*/
public class UserDAOImpl implements UserDAO { SqlSessionFactory sqlSessionFactory;
/**
* 向DAO实现类中注入SqlSessionFactory(此处通过构造方法注入)
*/
public UserDAOImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
} @Override
public User findUserById(int id) throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("test.findUserById", id);
sqlSession.close();
return user;
} @Override
public void insertUser(User user) throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.insert("test.insertUser", user);
sqlSession.commit();
sqlSession.close();
} @Override
public void deleteUser(int id) throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.delete("test.deleteUser", id);
sqlSession.commit();
sqlSession.close();
} }
3、新建一个源代码目录命名为test,在UserDAOImpl
类中鼠标右键新建一个Junit Test Case,更换源代码目录为test并勾选我们需要测试的方法:
public class UserDAOImplTest { private SqlSessionFactory sqlSessionFactory; /**
* 此方法在执行测试之前执行,得到一个SqlSessionFactory
*/
@Before
public void setUp() throws Exception { sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml"));
} @Test
public void testFindUserById() throws Exception {
// 创建UserDAO(在构造中注入SqlSessionFactory)
UserDAO userDAO = new UserDAOImpl(sqlSessionFactory);
User user = userDAO.findUserById(1);
System.out.println(user);
} @Test
public void testInsertUser() throws Exception {
UserDAO userDAO = new UserDAOImpl(sqlSessionFactory);
User user = new User();
user.setSex("2");
user.setUsername("孙悟空");
user.setAddress("方寸灵台山");
user.setBirthday(new Date());
userDAO.insertUser(user);
} @Test
public void testDeleteUser() throws Exception {
UserDAO userDAO = new UserDAOImpl(sqlSessionFactory);
userDAO.deleteUser(27);
} }
原始DAO开发中存在的问题
DAO的接口实现类中存在大量的模板方法,设想:可以将重复的代码提取出来。
在SqlSession的方法时将Statement的id硬编码在你DAO的实现类中。
调用sqlSession的相关方法传入参数是泛型,即使传入错误的参数,在编译阶段也不会报错,不利于程序员开发。
Mapper动态代理方式
实现原理
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper接口开发需要遵循以下规范:Mapper可以自动生成Mapper接口实现类代理对象。
1、 Mapper.xml文件中的namespace与mapper接口的类路径相同。
2、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
1、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进行分类化管理,注意:使用mapper代理方法开发,namespace有特殊重要作用 -->
<mapper namespace="com.yihaomen.mybatis.dao.IUserOperation">
<!-- 在映射文件中配置很多sql -->
<!-- id标识映射文件的sql,称为statement的id ,将sql语句封装到mappedStatement对象中,所以将id称为statement的id
parameterType:指定输入类型 resultType:指定sql输出结果的所映射的java对象,select指定resultType表示将单挑记录
映射成java对象-->
<select id="selectUserByID" parameterType="int" resultType="User">
select * from `user` where id = #{id}
</select> <insert id="addUser" parameterType="User"
useGeneratedKeys="true" keyProperty="id">
insert into user(userName,userAge,userAddress) values(#{userName},#{userAge},#{userAddress})
</insert> <update id="updateUser" parameterType="User">
update user set userName=#{userName},userAge=#{userAge},userAddress=#{userAddress} where id=#{id}
</update> <delete id="deleteUser" parameterType="int">
delete from user where id=#{id}
</delete> <select id="list" resultType="User">
select * from `user`
</select> <!-- ${}表示拼接sql串,指定就是单挑记录所映射的java对象类型,使用${}拼接,容易导致sql注入
${value}:拼接输入参数的内容,如果传入类型是简单类型,${}中只能使用value -->
<select id="findUserByName" parameterType="String" resultType="User">
select * from `user` where username like '%${value}%'
</select>
</mapper>
2、UserMapper.java类
package com.yihaomen.mybatis.dao; import java.util.List; import com.yihaomen.mybatis.model.Article;
import com.yihaomen.mybatis.model.User; //注意:接口名字必须与 xml中的namespace名字一样 2、接口实现方法每个名字 与xml中的id对应
public interface IUserOperation {
//查询数据
public User selectUserByID(int id);
//增加数据
public void addUser(User user);
//更新数据
public void updateUser(User user);
//删除数据
public void deleteUser(int id);
//联合查询
public List<Article> getUserArticles(int id);
//list获取
public List<User> list();
//模糊查询
public List<User> findUserByName(String name); }
完成前面2步之后不要忘了在映射文件SqlMapConfig.xml中加载UserMapper.xml哦!
<!-- 配置映射文件 -->
<mappers>
<mapper resource="sqlmap/User.xml"/>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
3、针对UserMapper接口测试
package com.yihaomen.mybatis.ui; import java.io.Reader;
import java.util.List; import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder; import com.yihaomen.mybatis.dao.IUserOperation;
import com.yihaomen.mybatis.model.User; public class Test {
private static SqlSessionFactory sqlSessionFactory;
private static Reader reader; //创建会话工厂,传入mybatis的配置文件信息
static{
try{
//得到配置文件流
reader = Resources.getResourceAsReader("Configuration.xml");
//创建会话工厂,传入mybatis的配置文件信息
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); }catch(Exception e){
e.printStackTrace();
}
}
//公共方法,返回初始化的sqlSessionFactory对象
public static SqlSessionFactory getSession(){
return sqlSessionFactory;
} //查询数据
public void select() {
//通过工厂得到sqlsession
SqlSession session = sqlSessionFactory.openSession();
try {
//通过SqlSession操作数据库
//第一个参数:映射文件中statement的id
//第二个参数:指定和映射文件所匹配的parameterType类型参数
User user = (User) session.selectOne("com.yihaomen.mybatis.model.User.selectUserByID", 1);
System.out.println(user.getUserAddress());
System.out.println(user.getUserName());
} finally {
session.close();
}
} //增加数据
public void addUser(String address,String name){
//创建user对象
User user=new User();
user.setUserAddress(address);
user.setUserName(name);
user.setUserAge(80); //通过工厂得到SqlSession
SqlSession session = sqlSessionFactory.openSession();
try {
IUserOperation userOperation=session.getMapper(IUserOperation.class);
//添加数据
userOperation.addUser(user);
//提交
session.commit();
//System.out.println("当前增加的用户 id为:"+user.getId());
} finally {
session.close();
}
} //更新数据
public void updateUser(int id,String address){
//先得到用户,然后修改,提交。
SqlSession session = sqlSessionFactory.openSession();
try {
IUserOperation userOperation = session.getMapper(IUserOperation.class);
User user = userOperation.selectUserByID(id);
user.setUserAddress(address);
userOperation.updateUser(user);
session.commit();
System.out.println("更新成功!!");
} finally {
session.close();
}
} //删除数据
public void deleteUser(int id) {
SqlSession session = sqlSessionFactory.openSession(); try{
IUserOperation userOperation = session.getMapper(IUserOperation.class);
userOperation.deleteUser(id);
session.commit();
System.out.println("删除数据:id= "+id);
}finally {
session.close();
} } //list获取
public void getList() {
SqlSession session = sqlSessionFactory.openSession(); try{
IUserOperation userOperation = session.getMapper(IUserOperation.class);
List<User> us = userOperation.list();
session.commit();
//System.out.println("生成list: "+us.size());
}finally {
session.close();
} } //模糊查询
public void geFindUserByName(String name) {
SqlSession session = sqlSessionFactory.openSession(); try{
IUserOperation userOperation = session.getMapper(IUserOperation.class);
List<User> us = userOperation.findUserByName(name);
System.out.println(us.size());
session.commit(); }finally {
session.close();
} } public static void main(String[] args) {
Test test = new Test();
//test.getList();
test.geFindUserByName("小");
//test.addUser("杭州","小江"); } }
我们比较疑问的就是我们在UserMapper.xml的根据用户名查找用户的ResultType使用的是普通的POJO,但是我们自己的Mapper接口中返回值是List类型。这不就造成了类型不一致么?但是,实际上代理对象内部调用了
selectOne()
或者selectList()
,代理对象内部会自动进行判断是否是单独的POJO选用合适的方法。Mapper接口中方法的参数只有一个是否会影响系统的维护?DAO层的代码是被业务层公用的,即使Mapper接口的参数只有一个我们也可以使用包装的POJO来满足系统需求。
注意:持久层中方法的参数中可以使用包装类型,但是Service层中不建议使用包装类型(不利于业务层的拓展维护)。
Mybatis学习笔记(三) 之Dao开发的更多相关文章
- Mybatis学习笔记(三) —— DAO开发方法
一.SqlSession的使用范围 SqlSession中封装了对数据库的操作,如:查询.插入.更新.删除等. SqlSession通过SqlSessionFactory创建. SqlSessionF ...
- 【MyBatis学习03】原始dao开发方法及其弊端
上一篇博文总结了一下mybatis的入门,接下来就要开发dao方法了,这篇博文主要总结一下mybatis中原始dao开发的方法,最后并总结一下原始dao开发方法的弊端.mybatis中dao开发应该使 ...
- MyBatis学习笔记(三) Configuration类
一.初探Configuration类 我们先来看一下MyBatis的XML配置文件的结构,(摘自mybatis.org) 下面这个是Configuration类的部分变量 一点不一样是不是??? 其实 ...
- MyBatis学习笔记(三) 关联关系
首先给大家推荐几个网页: http://blog.csdn.net/isea533/article/category/2092001 没事看看 - MyBatis工具:www.mybatis.tk h ...
- mybatis学习笔记三(关联关系)
学习mybatis的关联关系,主要注解在代码上,这里不做解释.配置文件一样的就不贴了 1.关联关系表创建(学生对应老师 多对一) 学生老师表 2.表对应的实体类 package com.home.en ...
- MyBatis学习笔记(三)——优化MyBatis配置文件中的配置
转自孤傲苍狼的博客:http://www.cnblogs.com/xdp-gacl/p/4264301.html 一.连接数据库的配置单独放在一个properties文件中 之前,我们是直接将数据库的 ...
- Mybatis学习笔记之---编写dao实现类的CRUD
Mybatis编写dao实现类的CRUD 1.pom.xml <dependencies> <dependency> <groupId>junit</grou ...
- Mybatis学习笔记三
一.延迟加载 延迟加载即加载延迟了,并不是一次性加载完而是按需加载,感觉应该是针对多表查询而言的,即先查询单表等需要另一张表的信息时再去加载,这样能提高数据库的性能: 需要注意的是,mybatis提供 ...
- mybatis学习笔记(三)-- 优化数据库连接配置
原来直接把数据库连接配置信息写在conf.xml配置中,如下 <?xml version="1.0" encoding="UTF-8"?> < ...
- mybatis 学习笔记(三):mapper 代理开发 dao 层
mybatis 学习笔记(三):mapper 代理开发 dao 层 优势 通过使用mapper 代理,我们可以不需要去编写具体的实现类(使用 getMapper() 方法自动生成),只需编写接口即可, ...
随机推荐
- swift 笔记 (二十) —— 泛型
泛型 泛型是为了解决在针对不同数据类型.而做了同一种功能的操作导致的每一个类型我们都要写一份代码的问题. 有了泛型,我们能够仅仅写一份逻辑代码,而适应于不同的数据类型. func swapInt(in ...
- javascript 10进制和64进制的转换
原文:javascript 10进制和64进制的转换 function string10to64(number) { var chars = '0123456789abcdefghigklmnopqr ...
- 非接触式电子音乐控制器CHIMAERA
本篇文章,我将介绍个有意思的设备. 她就是Chimaera,一个基于电磁场效应的非接触式电子音乐控制器. <弹奏Chimaera的声音> 霍尔效应传感器阵列及其周围部件组成了一个连续的2D ...
- 如何防范CC攻击
服务器如何防范CC攻击CC攻击是DDOS(分布式拒绝服务)的一种,相比其它的DDOS攻击CC似乎更有技术含量一些.这种攻击你见不到虚假IP,见不到特别大的异常流量,但造成服务器无法进行正常连接,听说一 ...
- jquery扩展方法案例
-----------------扩展方法: $.extend({ "max": function (a, b) { if (a > b) return a; }, &quo ...
- 什么是PHP
PHP(PHP: Hypertext Preprocessor的缩写,中文名:“超文本预处理器”)是一种通用开源脚本语言.语法吸收了C语言.Java和Perl的特点,入门门槛较低,易于学习,使用广泛, ...
- VS2010生成安装包制作步骤
VS2010生成安装包制作步骤 在VS2010中文旗舰版本中生成winForm安装包,可以复制你电脑中的开发环境,避免你忘记了一下配置然后在别的机器上运行不起来.也省去了Framwork的安装. ...
- MVC应用程序请求密码的功能(二)
MVC应用程序请求密码的功能(二) 在完成<MVC应用程序请求密码的功能(一)>http://www.cnblogs.com/insus/p/3471534.html之后,如果你照着做,所 ...
- 二分法-C++
对于一个非线性方程f(x)=0求改方程的根,我们的思路可以这么想: 1.根的存在性.若该方程没有根,何必徒劳想法设法去求它的解呢?对于一个方程,我们怎么去找他的根,有连续函数零点定理可知:若有f(a) ...
- C语言基础复习总结
C语言基础复习总结 大一学的C++,不过后来一直没用,大多还给老师了,最近看传智李明杰老师的ios课程的C语言入门部分,用了一周,每晚上看大概两小时左右,效果真是顶一学期的课,也许是因为有开发经验吧, ...