原始 dao 开发方法和 mapper 代理方法的比较。
原文地址
原始dao开发方法 DAO接口类UserDAO.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.mybatis.dao;import java.util.List;import com.mybatis.entity.User;public interface UserDAO { public User findUserById (Integer id) ; public List<User> findUserByName (String username) ; public void insertUser (User user) ; public void deleteUser (Integer id) ; public void updateUser (User user) ; }
dao实现类UserDaoImpl.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 package com.mybatis.dao;import java.util.List;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import com.mybatis.entity.User;public class UserDaoImpl implements UserDAO { private SqlSessionFactory sqlSessionFactory; public UserDaoImpl (SqlSessionFactory sqlSessionFactory) { this .sqlSessionFactory = sqlSessionFactory; } @Override public User findUserById (Integer id) { SqlSession sqlSession = sqlSessionFactory.openSession(); User user = sqlSession.selectOne("test.findUserById" , id); sqlSession.close(); return user; } @Override public List<User> findUserByName (String username) { SqlSession sqlSession = sqlSessionFactory.openSession(); List<User> list = sqlSession.selectList("test.findUserByName" , username); sqlSession.commit(); sqlSession.close(); return list; } @Override public void insertUser (User user) { SqlSession sqlSession = sqlSessionFactory.openSession(); sqlSession.insert("test.insertUser" , user); sqlSession.commit(); sqlSession.close(); } @Override public void deleteUser (Integer id) { SqlSession sqlSession = sqlSessionFactory.openSession(); sqlSession.delete("test.deleteUser" , id); sqlSession.commit(); sqlSession.close(); } @Override public void updateUser (User user) { SqlSession sqlSession = sqlSessionFactory.openSession(); sqlSession.update("test.updateUser" , user); sqlSession.commit(); sqlSession.close(); } }
JunitTest测试UserDaoImplTest.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 package com.mybatis.dao.test;import java.io.InputStream;import java.util.Date;import java.util.List;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.Before;import org.junit.Test;import com.mybatis.dao.UserDaoImpl;import com.mybatis.entity.User;public class UserDaoImplTest { private SqlSessionFactory sqlSessionFactory; @Before public void setUp () throws Exception { String resource = "SqlMapConfig.xml" ; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void findUserByIdTest () { UserDaoImpl userDao = new UserDaoImpl(sqlSessionFactory); User user = userDao.findUserById(1 ); System.out.println(user); } @Test public void findUserByNameTest () { UserDaoImpl userDao = new UserDaoImpl(sqlSessionFactory); List<User> list = userDao.findUserByName("小" ); System.out.println(list); } @Test public void insertUserTest () { UserDaoImpl userDao = new UserDaoImpl(sqlSessionFactory); User user = new User(); user.setUsername("张三丰" ); user.setSex("1" ); user.setBirthday(new Date()); user.setAddress("武当山" ); userDao.insertUser(user); } @Test public void deleteUserTest () { UserDaoImpl userDao = new UserDaoImpl(sqlSessionFactory); userDao.deleteUser(8 ); } @Test public void updateUserTest () { UserDaoImpl userDao = new UserDaoImpl(sqlSessionFactory); User user = new User(); user.setId(1 ); user.setUsername("王六" ); user.setSex("2" ); user.setAddress("天津" ); user.setBirthday(new Date()); userDao.updateUser(user); } }
小结 该方法存在以下几个问题:
dao接口中存在大量模版方法,能否把这些代码提出来,减少我们的工作量
调用sqlSession方法时将statement的id硬编码了
调用sqlSession传入的变量,由于sqlSession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序开发。
所以我们带着这几个问题看看mapper代理开发的方法,是否能解决这些问题呢?
mapper代理方法(只需要mapper接口,相当于dao接口) 概要:
编写XXXmapper.xml的映射文件
编写mapper接口需要遵循一些开发规范,mybatis可以自动生成mapper接口实现类代理对象。
开发规范:
在XXXmapper.xml中namespace等于mapper接口地址。
XXXmapper.java接口中的方法和mapper.xml中的statement的Id一致。
mapper.java接口中的方法输入参数和mapper.xml中statement的parameterType指定的类型一致。
mapper.java接口中的方法的返回值类型和mapper.xml中statement的resultType指定的类型一致。
以上的开发规范主要是对下面的代码进行统一生成
1 2 3 SqlSession sqlSession = sqlSessionFactory.openSession(); User user = sqlSession.selectOne("test.findUserById" , id); ......
UserMapper.java类代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package com.mybatis.mapper;import java.util.List;import com.mybatis.entity.User;public interface UserMapper { public User findUserById (int id) ; public List<User> findUserByName (String username) ; public void insertUser (User user) ; public void deleteUser (Integer id) ; public void updateUser (User user) ; }
将原来的User.xml拷贝修改名称为UserMapper.xml,只需修改此行代码即可 1 2 3 4 <mapper namespace ="com.mybatis.mapper.UserMapper" >
在SqlMapConfig.xml中加载UserMapper.xml 1 2 3 4 5 <mappers > <mapper resource ="sqlmap/User.xml" /> <mapper resource ="mapper/UserMapper.xml" /> </mappers >
Junit测试UserMapperTest.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 package com.mybatis.dao.test;import java.io.InputStream;import java.util.Date;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 org.junit.Before;import org.junit.Test;import com.mybatis.entity.User;import com.mybatis.mapper.UserMapper;public class UserMapperTest { private SqlSessionFactory sqlSessionFactory; @Before public void setUp () throws Exception { String resource = "SqlMapConfig.xml" ; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void testFindUserById () { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class ) ; User user = mapper.findUserById(1 ); System.out.println(user); sqlSession.close(); } @Test public void testFindUserByName () { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class ) ; List<User> list = mapper.findUserByName("小" ); System.out.println(list); sqlSession.close(); } @Test public void testDeleteUser () { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class ) ; mapper.deleteUser(6 ); sqlSession.commit(); sqlSession.close(); } @Test public void testInsertUser () { SqlSession sqlSession = sqlSessionFactory.openSession(); User user = new User(); user.setUsername("者别" ); user.setSex("1" ); user.setAddress("蒙古乞颜部落" ); user.setBirthday(new Date()); UserMapper mapper = sqlSession.getMapper(UserMapper.class ) ; mapper.insertUser(user); sqlSession.commit(); sqlSession.close(); } @Test public void testUpdateUser () { SqlSession sqlSession = sqlSessionFactory.openSession(); User user = new User(); user.setId(11 ); user.setUsername("神箭手者别" ); user.setSex("1" ); user.setAddress("蒙古乞颜部落" ); user.setBirthday(new Date()); UserMapper mapper = sqlSession.getMapper(UserMapper.class ) ; mapper.updateUser(user); sqlSession.commit(); sqlSession.close(); } }
小结
代理对象内部调用selectOne()和selectList(): 如果mapper对象返回单个pojo对象(非集合对象)代理对象内部通过selectOne查询数据库,如果mapper方法返回集合对象,代理对象内部通过selectList查询数据库。
mapper接口中的方法参数只能有一个是否影响系统开发:
mapper接口方法参数只能有一个,系统是否不利于维护?
回答:系统框架中,dao层的代码是被业务层公用的。即使mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求。