本文讲解SqlSession,并对两种方法(原始dao开发和mapper代理开发)分别做简单展示
SqlSession使用范围
通过SqlSessionFactoryBuilder
创建会话工厂SqlSessionFactory
将SqlSessionFactoryBuilder
当成一个工具类使用即可,不需要使用单例管理SqlSessionFactoryBuilder
。在需要创建SqlSessionFactory
时候,只需要new一次SqlSessionFactoryBuilder
即可。
通过SqlSessionFactory
创建SqlSession
,使用单例模式管理sqlSessionFactory
(工厂一旦创建,使用一个实例)。将来mybatis和spring整合后,使用单例模式管理sqlSessionFactory
。
SqlSession
是一个面向用户(程序员)的接口。SqlSession中提供了很多操作数据库的方法:如:selectOne
(返回单个对象)、selectList
(返回单个或多个对象)。
SqlSession
是线程不安全的,在SqlSesion
实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性。
SqlSession
最佳应用场合在方法体内,定义成局部变量使用。
原始dao开发方法 程序员需要写dao接口和dao实现类
dao接口 1 2 3 4 5 6 7 8 9 10 11 12 13 public interface UserDao { public User findUserById (int id) throws Exception ; public List<User> findUserByName (String name) throws Exception ; public void insertUser (User user) throws Exception ; public void deleteUser (int id) throws Exception ; }
dao接口实现类 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 package com.iot.mybatis.dao;import com.iot.mybatis.po.User;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import java.util.List;public class UserDaoImpl implements UserDao { private SqlSessionFactory 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 List<User> findUserByName (String name) throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); List<User> list = sqlSession.selectList("test.findUserByName" , name); sqlSession.close(); return list; } @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(); } }
测试代码 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 package com.iot.mybatis.dao;import java.io.InputStream;import com.iot.mybatis.po.User;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;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 testFindUserById () throws Exception { UserDao userDao = new UserDaoImpl(sqlSessionFactory); User user = userDao.findUserById(1 ); System.out.println(user); } }
总结原始dao开发问题 1.dao接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量。
2.调用sqlsession方法时将statement的id硬编码了
3.调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。
mapper代理方法 程序员只需要mapper接口(相当 于dao接口)
程序员还需要编写mapper.xml映射文件
程序员编写mapper接口需要遵循一些开发规范,mybatis可以自动生成mapper接口实现类代理对象。
开发规范
在mapper.xml中namespace等于mapper接口地址
1 2 3 4 5 <mapper namespace ="com.iot.mybatis.mapper.UserMapper" >
mapper.java接口中的方法名和mapper.xml中statement的id一致
mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致。
mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致。
1 2 3 <select id ="findUserById" parameterType ="int" resultType ="com.iot.mybatis.po.User" > SELECT * FROM user WHERE id=#{value} </select >
1 2 public User findUserById (int id) throws Exception ;
总结:以上开发规范主要是对下边的代码进行统一生成:
1 2 User user = sqlSession.selectOne("test.findUserById" , id); sqlSession.insert("test.insertUser" , user);
代码
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 <?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 ="com.iot.mybatis.mapper.UserMapper" > <select id ="findUserById" parameterType ="int" resultType ="com.iot.mybatis.po.User" > SELECT * FROM user WHERE id=#{value} </select > <select id ="findUserByName" parameterType ="java.lang.String" resultType ="com.iot.mybatis.po.User" > SELECT * FROM user WHERE username LIKE '%${value}%' </select > <insert id ="insertUser" parameterType ="com.iot.mybatis.po.User" > <selectKey keyProperty ="id" order ="AFTER" resultType ="java.lang.Integer" > SELECT LAST_INSERT_ID() </selectKey > INSERT INTO user (username,birthday,sex,address)values (#{username},#{birthday},#{sex},#{address}) </insert > <delete id ="deleteUser" parameterType ="java.lang.Integer" > delete from user where id=#{id} </delete > <update id ="updateUser" parameterType ="com.iot.mybatis.po.User" > update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id} </update > </mapper >
1 2 3 <mappers > <mapper resource ="mapper/UserMapper.xml" /> </mappers >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public interface UserMapper { public User findUserById (int id) throws Exception ; public List<User> findUserByName (String name) throws Exception ; public void insertUser (User user) throws Exception ; public void deleteUser (int id) throws Exception ; public void updateUser (User user) throws Exception ; }
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 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 () throws Exception { SqlSession sqlSession=sqlSessionFactory.openSession(); UserMapper userMapper=sqlSession.getMapper(UserMapper.class); User user=userMapper.findUserById(1 ); System.out.println(user.getUsername()); } }
一些问题总结
代理对象内部调用selectOne
或selectList
如果mapper方法返回单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库。
如果mapper方法返回集合对象,代理对象内部通过selectList查询数据库。
mapper接口方法参数只能有一个是否影响系统开发
mapper接口方法参数只能有一个,系统是否不利于扩展维护?系统框架中,dao层的代码是被业务层公用的。即使mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求。
注意:持久层方法的参数可以包装类型、map…等,service方法中建议不要使用包装类型(不利于业务层的可扩展)。