基础知识:
1).SqlSessionFactoryBuilder:
通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory。将SqlSessionFactoryBuilder当成一个工具类使用即可,不需要使用单例管理SqlSessionFactoryBuilder。
在需要创建SqlSessionFactory时候,只需要new一次SqlSessionFactoryBuilder即可。
2).SqlSessionFactory:
通过SqlSessionFactory创建SqlSession,使用单例模式管理sqlSessionFactory(工厂一旦创建,使用一个实例)。将来mybatis和spring整合后,使用单例模式管理sqlSessionFactory。
3).SqlSession:
SqlSession是一个面向用户(程序员)的接口。
SqlSession中提供了很多操作数据库的方法:如:selectOne(返回单个对象)、selectList(返回单个或多个对象)、。
SqlSession是线程不安全的,在SqlSesion实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性。
SqlSession最佳应用场合在方法体内,定义成局部变量使用。
一、原始dao开发方法()
需要编写dao接口和实现类;
dao接口:
1 package com.cy.Dao; 2 3 import java.util.List; 4 5 import com.cy.po.User; 6 7 /** 8 * dao接口,用户管理 9 * @author chengyu 10 * 11 */ 12 public interface UserDao { 13 //根据id查询用户信息 14 public User findUserById(int id) throws Exception; 15 16 //根据用户名列查询用户列表 17 public List<User> findUserByName(String name) throws Exception; 18 19 //添加用户信息 20 public void insertUser(User user) throws Exception; 21 22 //删除用户信息 23 public void deleteUser(int id) throws Exception; 24 }
dao接口实现类:
1 package com.cy.Dao; 2 3 import java.util.List; 4 5 import org.apache.ibatis.session.SqlSession; 6 import org.apache.ibatis.session.SqlSessionFactory; 7 8 import com.cy.po.User; 9 10 /** 11 * dao接口实现类 12 * @author chengyu 13 * 14 */ 15 public class UserDaoImpl implements UserDao { 16 // 需要向dao实现类中注入SqlSessionFactory 17 // 这里通过构造方法注入 18 private SqlSessionFactory sqlSessionFactory; 19 20 public UserDaoImpl(SqlSessionFactory sqlSessionFactory) { 21 this.sqlSessionFactory = sqlSessionFactory; 22 } 23 24 @Override 25 public User findUserById(int id) throws Exception { 26 SqlSession sqlSession = sqlSessionFactory.openSession(); 27 User user = sqlSession.selectOne("test.findUserById", id); 28 29 // 释放资源 30 sqlSession.close(); 31 return user; 32 } 33 34 @Override 35 public List<User> findUserByName(String name) throws Exception { 36 SqlSession sqlSession = sqlSessionFactory.openSession(); 37 List<User> list = sqlSession.selectList("test.findUserByName", name); 38 sqlSession.close(); 39 return list; 40 } 41 42 @Override 43 public void insertUser(User user) throws Exception { 44 SqlSession sqlSession = sqlSessionFactory.openSession(); 45 sqlSession.insert("test.insertUser", user); 46 sqlSession.commit(); 47 sqlSession.close(); 48 49 } 50 51 @Override 52 public void deleteUser(int id) throws Exception { 53 SqlSession sqlSession = sqlSessionFactory.openSession(); 54 sqlSession.delete("test.deleteUser", id); 55 sqlSession.commit(); 56 sqlSession.close(); 57 } 58 59 }
测试程序:
1 package com.cy.Dao; 2 3 import static org.junit.Assert.*; 4 5 import java.io.InputStream; 6 7 import org.apache.ibatis.io.Resources; 8 import org.apache.ibatis.session.SqlSessionFactory; 9 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 10 import org.junit.Before; 11 import org.junit.Test; 12 13 import com.cy.po.User; 14 15 public class UserDaoImplTest { 16 private SqlSessionFactory sqlSessionFactory; 17 18 // 此方法是在执行testFindUserById之前执行 19 @Before 20 public void setUp() throws Exception { 21 // mybatis配置文件 22 String resource = "SqlMapConfig.xml"; 23 // 得到配置文件流 24 InputStream inputStream = Resources.getResourceAsStream(resource); 25 26 // 创建会话工厂,传入mybatis的配置文件信息 27 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 28 } 29 30 @Test 31 public void testFindUserById() throws Exception { 32 // 创建UserDao的对象 33 UserDao userDao = new UserDaoImpl(sqlSessionFactory); 34 35 // 调用UserDao的方法 36 User user = userDao.findUserById(1); 37 38 System.out.println(user); 39 } 40 41 }
原始的dao开发方法问题总结:
1)dao接口实现类方法中存在大量模板方法。
2)调用sqlsession方法时将statement的id硬编码了
3)调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于开发。
二、使用mapper接口(相当于dao接口)代理开发方法:
开发规范:遵循这些开发规范,mybatis可以自动生成mapper接口实现类代理对象。
1)在mapper.xml中namespace等于mapper接口地址
2)mapper.java接口中的方法名和mapper.xml中statement的id一致
3)mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致
4)mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致
UserMapper接口:
1 package com.cy.mapper; 2 3 import java.util.List; 4 5 import com.cy.po.User; 6 7 /** 8 * mapper接口,用户管理 9 * @author chengyu 10 * 11 */ 12 public interface UserMapper { 13 //根据id查询用户信息 14 public User findUserById(int id) throws Exception; 15 16 //根据用户名列查询用户列表 17 public List<User> findUserByName(String name)throws Exception; 18 19 //插入用户 20 public void insertUser(User user)throws Exception; 21 22 //删除用户 23 public void deleteUser(int id)throws Exception; 24 }
UserMapper.xml:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 6 <!--使用mapper代理方法开发,namespace有特殊重要的作用,namespace等于mapper接口地址--> 7 <mapper namespace="com.cy.mapper.UserMapper"> 8 <!--通过id查询用户 --> 9 <select id="findUserById" parameterType="int" resultType="com.cy.po.User"> 10 SELECT * FROM USER WHERE id=#{value} 11 </select> 12 13 <!-- 根据用户名称模糊查询用户信息,可能返回多条--> 14 <select id="findUserByName" parameterType="java.lang.String" resultType="com.cy.po.User"> 15 SELECT * FROM USER WHERE username LIKE '%${value}%' 16 </select> 17 18 <!-- 添加用户 --> 19 <insert id="insertUser" parameterType="com.cy.po.User"> 20 <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> 21 SELECT LAST_INSERT_ID() 22 </selectKey> 23 insert into user(username,birthday,sex,address) value(#{username},#{birthday},#{sex},#{address}) 24 </insert> 25 26 <!-- 根据id删除 用户--> 27 <delete id="deleteUser" parameterType="java.lang.Integer"> 28 delete from user where id=#{id} 29 </delete> 30 31 <!-- 根据id更新用户 --> 32 <update id="updateUser" parameterType="com.cy.po.User"> 33 update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} 34 where id=#{id} 35 </update> 36 </mapper>
将UserMapper.xml映射文件加入:
<!-- 加载 映射文件 --> <mappers> <mapper resource="mapper/UserMapper.xml"/> </mappers>
UserMapper接口的测试方法:
1 package com.cy.mapper; 2 3 import static org.junit.Assert.*; 4 5 import java.io.InputStream; 6 import java.util.List; 7 8 import org.apache.ibatis.io.Resources; 9 import org.apache.ibatis.session.SqlSession; 10 import org.apache.ibatis.session.SqlSessionFactory; 11 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 12 import org.junit.Before; 13 import org.junit.Test; 14 15 import com.cy.po.User; 16 17 public class UserMapperTest { 18 19 private SqlSessionFactory sqlSessionFactory; 20 21 @Before 22 public void setUp() throws Exception { 23 24 String resource = "SqlMapConfig.xml"; 25 InputStream inputStream = Resources.getResourceAsStream(resource); 26 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 27 } 28 29 @Test 30 public void testFindUserById() throws Exception { 31 SqlSession sqlSession = sqlSessionFactory.openSession(); 32 33 //创建UserMapper对象,mybatis自动生成mapper代理对象 34 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 35 36 User user = userMapper.findUserById(1); 37 System.out.println(user); 38 } 39 @Test 40 public void testFindUserByName() throws Exception { 41 SqlSession sqlSession = sqlSessionFactory.openSession(); 42 43 //创建UserMapper对象,mybatis自动生成mapper代理对象 44 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 45 46 List<User> list = userMapper.findUserByName("小明"); 47 sqlSession.close(); 48 System.out.println(list); 49 } 50 }
关于mapper接口代理开发的一些问题:
1.代理对象内部是调用selectOne还是selectList?
如果mapper方法返回单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库。
如果mapper方法返回集合对象,代理对象内部通过selectList查询数据库。
2、mapper接口方法参数只有一个是否影响开发?
系统框架中,dao层的代码是被业务层公用的。即使mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求。
注意:持久层方法的参数可以包装类型、map。。。,service方法中建议不要使用包装类型(不利于业务层的可扩展)。