思路:原始Dao开发方式需要程序员编写Dao接口和Dao实现类
由第一篇博客的架构图可知:
SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。
通过SqlSessionFactory创建SqlSession,而SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。
SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory生产,所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。
SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory。
SqlSession是一个面向用户的接口, sqlSession中定义了数据库操作方法。
每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的(因为SqlSession底层对应的是Connection连接)。因此最佳的范围是请求或方法范围。
**
UserDao接口
**
public interface UserDao {
/**
* 查全部
* @return
*/
public List<User> findAll();
/**
* 保存用户
* @param user
*/
public void save(User user);
/**
* 更新用户
* @param user
*/
public void update(User user);
/**
* 根据id删除用户
* @param id
*/
public void del(Integer id);
}
UserDaoImpl实现类
执行sql语句,从数据库中查询出来的数据封装到User对象中,返回结果集。
实现类中注入SqlSessionFactory,暂时通过构造方法注入。
在查询、更新等方法中创建SqlSession,因为SqlSession线程不安全。
执行增删改方法,SqlSession需要先commit再close。
public class UserDaoImpl implements UserDao {
//所有的方法共用的factory对象,应该是属于应用级别
private SqlSessionFactory sessionFactory;
public UserDaoImpl(SqlSessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public List<User> findAll() {
//每一个方法应该获取一个SqlSession对象,用完应该立即关闭,因为线程不安全
SqlSession sqlSession = sessionFactory.openSession();
List<User> userList = sqlSession.selectList("userMapper.findAll");
sqlSession.close();
return userList;
}
//执行增删改,sqlSession需要comnit操作
@Override
public void save(User user) {
SqlSession sqlSession = sessionFactory.openSession();
sqlSession.insert("userMapper.save",user);
sqlSession.commit();
sqlSession.close();
}
@Override
public void update(User user) {
SqlSession sqlSession = sessionFactory.openSession();
sqlSession.update("userMapper.update" , user);
sqlSession.commit();
sqlSession.close();
}
@Override
public void del(Integer id) {
SqlSession sqlSession = sessionFactory.openSession();
sqlSession.delete("userMapper.del",id);
sqlSession.commit();
sqlSession.close();
}
}
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">
<mapper namespace="userMapper">
<select id="findAll" resultType="com.itheima.domain.User">
select * from user
</select>
<insert id="save" parameterType="com.itheima.domain.User">
insert into user values(null ,"${username}",#{password},#{sex},#{address},#{birthday})
</insert>
<update id="update" parameterType="com.itheima.domain.User">
update user set username=#{username},password=#{password},sex=#{sex},address=#{address}
where id = #{id}
</update>
<delete id="del" parameterType="java.lang.Integer">
delete from user where id = #{value}
</delete>
</mapper>
由第一篇博客的架构图可知,总的配置文件SqlMapConfig.xml通过<mapper resource=…/>引入XXXMapper.xml映射文件,程序UserMapper.xml中的namespace+id作为底层Configuration类中Map<String,Mapper>的key来定位sql语句,用Mapper对象(其中包含sql,resultType,parameterType)作为value来存储sql。
SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatisdb_331"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/itheima/mapper/UserMapper.xml"/>
</mappers>
</configuration>
测试程序TestMybatisDao.java
public class TestMybatisDao {
SqlSessionFactory sqlSessionFactory = null;
@Before
public void init(){
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("SqlMapConfig.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindAll(){
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
List<User> userList = userDao.findAll();
for (User user : userList) {
System.out.println(user);
}
}
@Test
public void testSave(){
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
User user = new User();
user.setUsername("小明");
user.setPassword("xiaoming");
user.setSex("男");
user.setAddress("北京房山");
user.setBirthday("2018-08-08");
userDao.save(user);
}
}
传统Dao开发存在的问题:
- Dao实现类存在大量重复代码
- 调用SqlSession方法时,将statement的id(也就是namespace.id,比如userMapper.findAll)硬编码了
- SqlSession的方法中,要求传入的参数是Object类型的,也就是说,如果传错参数,运行时才会报错,不利于开发