在前面的学习中,我们是SqlSessionFactoryBuilder创建SqlSeesionFactory,SqlSeesionFactory可以用单例模式的方法,每次操作只用创建一次工厂就可以了,那么SqlSessionFactoryBuilder就相当于一个工具类来使用。最重要的就是sqlsession,它不能是单例的,它用来执行sql语句,语句中有数据属性,如果只有一个全局变量,在多线程的作用下是线程不安全的。所以在使用时,我们在方法内部使用,也就是一个方法,我们就是sqlsessionfatory创建一个sqlsession,保证数据安全一致
原始dao开发方法
程序要自己写dao接口以及它的实现类,然后向实现类中中注入SqlSeesionFactory,然后在每个方法中创建sqlsession,用来执行sql语句
dao接口
package xidian.lili.dao;
import java.io.IOException;
import java.util.List;
import xidian.lili.po.User;
public interface UserDao {
public User findUserById(int id) throws IOException;
public List<User> findUserByName(String username) throws IOException;
public void insertUser(User user) throws IOException;
public void deleteUserById(int id) throws IOException;
}
dao接口的实现类,通过构造方法注入sqlSessionFactory,
package xidian.lili.dao;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import xidian.lili.po.User;
public class UserDaoImpl implements UserDao {
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory=sqlSessionFactory;
}
@Override
public User findUserById(int id) throws IOException {
SqlSession sqlSession=sqlSessionFactory.openSession();
User user=sqlSession.selectOne("test.findUserById", id);
sqlSession.close();
return user;
}
@Override
public List<User> findUserByName(String username) throws IOException {
SqlSession sqlSession=sqlSessionFactory.openSession();
List<User> list=new ArrayList<User>();
list=sqlSession.selectList("test.findUserByName", username);
System.out.println(list);
sqlSession.close();
return list;
}
@Override
public void insertUser(User user) throws IOException {
SqlSession sqlSession=sqlSessionFactory.openSession();
sqlSession.insert("test.insertUser",user);
sqlSession.commit();
sqlSession.close();
}
@Override
public void deleteUserById(int id) throws IOException {
SqlSession sqlSession=sqlSessionFactory.openSession();
sqlSession.delete("test.deleteUserById", id);
sqlSession.commit();
sqlSession.close();
}
}
编写测试用例
package xidian.lili.dao;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.InputStream;
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 xidian.lili.po.User;
public class UserDaoImplTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception {
InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() throws IOException {
UserDao userDao=new UserDaoImpl(sqlSessionFactory);
User user=userDao.findUserById(1);
System.out.println(user);
}
}
结果正确,其中sqMapConfig.xml和User.xml文件还是与之前一样。
这样做的问题:
(1)可以看到在UserDao的实现类中,每个方法都有重复的代码
(2)在UserDao的实现类中,每个方法进行输入参数传递时就算参数类型不是我们想要的编译也不会报错
(3)在UserDao的实现类中,statement的id还是硬编码了,比如id变了,还是要修改源代码
Mapper代理开发DAO方法
可以看到,传统DAO的开发方法问题都是DAO接口的实现类中,在这里我们只需要编写Mapper接口(相当于DAO接口),然后通过一些定义的规范,mybatis会自动为我们生产代理对象,当然映射文件mapper.xml和全局配置文件不能少。
规范
- 在mapper.xml文件中,namespace要为Mapper接口的路径
- 在mapper接口中,方法名要与mapper.xml文件中的statement id 一致
- 在mapper接口中,方法参数类型要与mapper.xml文件中的parameterType类型一致
- 在mapper接口中,方法返回参数类型要与mapper.xml文件中的resultType类型一致
- 在前面我们还建议在sqlsession执行statement时,第一个参数最好是namespace.statmentid
- 这样我们就相当于为mybatis提供了方法的路径,通过反射自然能找到要执行的方法
根据这些规范我们来编写mapper接口和mapper.xml
然后对照UserMapper.xml以及上面写的规范我们编写Mapper接口中的方法
然后在全局配置文件中中加载UserMapper.xml文件
然后我们对UserMapper接口中的方法进行测试,通过sqlSession.getMapper(UserMapper.class),就获得接口UserMapper的对象,这就是mybatis自动为我们生成的代理对象,然后就可以调用接口的方法
但是Mapper代理的方式,我们注意到在Mapper接口的所有方法中就只能有一个参数,因为参数类型要与Mapper.xml文件的parameterType一致,解决办法我们可以把parameterType设置成po包装类型的对象,也就是创建一个po包装类,向它里面注入其他po类,再把这个包装的po对象传进去,就可以实现多个方法参数的意义