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
說明: 本文大部分內容都是跟隨者傳播智課的教學視頻學習而來,可以看做是翻譯文章,只是自己吸收之後又書寫一遍,加深自己的知識理解。