mybatis学习day2
SqlSession
位于sqlsessionfactory中 是 会话工厂的一部分 我们可以创建一个seesion来进行提交、回滚操作。
通过SqlSessionFactoryBuilder
创建会话工厂SqlSessionFactory
将SqlSessionFactoryBuilder
当成一个工具类使用即可,不需要使用单例管理SqlSessionFactoryBuilder
。在需要创建SqlSessionFactory
时候,只需要new一次SqlSessionFactoryBuilder
即可。
通过SqlSessionFactory
创建SqlSession
,使用单例模式管理sqlSessionFactory
(工厂一旦创建,使用一个实例)。将来mybatis和spring整合后,使用单例模式管理sqlSessionFactory
。
SqlSession
是一个面向用户(程序员)的接口。SqlSession中提供了很多操作数据库的方法:如:selectOne
(返回单个对象)、selectList
(返回单个或多个对象)。
SqlSession
是线程不安全的,在SqlSesion
实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性。
SqlSession
最佳应用场合在方法体内,定义成局部变量使用。
我们还记得mybatis的启动流程:
1.通过Resources处理得到一个字节流或者字符流的处理类
2.通过SqlSessionFactoryBuilder构建一个SqlSessionFactory
3.通过SqlSessionFactory得到SqlSession
4.通过SqlSession执行相关Mapper文件的sql语句
原始Dao层
UserDaoImpl
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
| package dao.Impl;
import dao.UserDao; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import po.User;
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(); } }
|
UserDao 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package dao;
import po.User;
import java.util.List;
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; }
|
注意:我改动了一些东西
相比于Day1 :
我将sqlmap改成Mapper层了 方便以后的学习和理解
记得将SqlMapConfig.xml中的注册改动一下
总结原始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);
|
代码
UserMapper.xml
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="mapper.UserMapper">
<select id="findUserById" parameterType="int" resultType="po.User"> SELECT * FROM users.user WHERE id=#{value} </select>
<select id="findUserByName" parameterType="java.lang.String" resultType="po.User"> SELECT * FROM users.user WHERE username LIKE '%${value}%' </select>
<insert id="insertUser" parameterType="po.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO users.user (username,birthday,sex,address)values (#{username},#{birthday},#{sex},#{address})
</insert>
<delete id="deleteUser" parameterType="java.lang.Integer"> delete from users.user where id=#{id} </delete>
<update id="updateUser" parameterType="po.User"> update users.user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id} </update>
</mapper>
|
mapper 文件夹下的 UserMapper (注意:该名字要和xml同名要不然找不到)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package mapper;
import po.User;
import java.util.List;
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; }
|
Test类
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
| import mapper.UserMapper; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Before; import org.junit.Test; import po.User;
import java.io.InputStream;
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方法中建议不要使用包装类型(不利于业务层的可扩展)。
- 在使用mybatis的selectList方法时,如果数据库的东西没东西返回,则不会为null 而是为空,而selectOne方法则会返回null
总结:数据库表字段如果有唯一约束,在mybatis中使用selectOne方法;
数据库表字段如果没有唯一约束,即使在业务逻辑上此字段时唯一的,但还是建议使用selectList方法。
如果数据库字段有唯一约束,那么你再添加相同的数据,则无法添加成功,但如果没有唯一约束,程序上可能出现并发,添加到数据库可以成功,但再次查询时会因为返回多条数据而导致程序出现问题。