mybatis学习day2

SqlSession

位于sqlsessionfactory中 是 会话工厂的一部分 我们可以创建一个seesion来进行提交、回滚操作。

image-20231219004632507

  • SqlSessionFactoryBuilder

通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactorySqlSessionFactoryBuilder当成一个工具类使用即可,不需要使用单例管理SqlSessionFactoryBuilder。在需要创建SqlSessionFactory时候,只需要new一次SqlSessionFactoryBuilder即可。

  • SqlSessionFactory

通过SqlSessionFactory创建SqlSession,使用单例模式管理sqlSessionFactory(工厂一旦创建,使用一个实例)。将来mybatis和spring整合后,使用单例模式管理sqlSessionFactory

  • SqlSession

SqlSession是一个面向用户(程序员)的接口。SqlSession中提供了很多操作数据库的方法:如:selectOne(返回单个对象)、selectList(返回单个或多个对象)。

SqlSession是线程不安全的,在SqlSesion实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性。

SqlSession最佳应用场合在方法体内,定义成局部变量使用。

我们还记得mybatis的启动流程:

1.通过Resources处理得到一个字节流或者字符流的处理类

2.通过SqlSessionFactoryBuilder构建一个SqlSessionFactory

3.通过SqlSessionFactory得到SqlSession

4.通过SqlSession执行相关Mapper文件的sql语句

原始Dao层

image-20231220202005658

UserDaoImpl
[code]
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 { // 需要向dao实现类中注入SqlSessionFactory // 这里通过构造方法注入 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 findUserByName(String name) throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); List 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(); }}
[/code]

UserDao 接口
[code]
package dao;import po.User;import java.util.List;public interface UserDao { //根据id查询用户信息 public User findUserById(int id) throws Exception; //根据用户名列查询用户列表 public List findUserByName(String name) throws Exception; //添加用户信息 public void insertUser(User user) throws Exception; //删除用户信息 public void deleteUser(int id) throws Exception;}
[/code]

注意:我改动了一些东西

相比于Day1 :

image-20231220202156033

我将sqlmap改成Mapper层了 方便以后的学习和理解

记得将SqlMapConfig.xml中的注册改动一下

image-20231220202312303

image-20231220202326507

总结原始Dao层开发的问题

1.dao接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量。

2.调用sqlsession方法时将statement的id硬编码了

3.调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。

Mapper代理方法

程序员只需要mapper接口(相当 于dao接口)

程序员还需要编写mapper.xml映射文件

程序员编写mapper接口需要遵循一些开发规范,mybatis可以自动生成mapper接口实现类代理对象。

开发规范

  • 在mapper.xml中namespace等于mapper接口地址

[code]

[/code]

  • mapper.java接口中的方法名和mapper.xml中statement的id一致
  • mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致。
  • mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致。

[code]

[/code]
[code]
//根据id查询用户信息public User findUserById(int id) throws Exception;
[/code]

总结:以上开发规范主要是对下边的代码进行统一生成:
[code]
User user = sqlSession.selectOne(“test.findUserById”, id);sqlSession.insert(“test.insertUser”, user);
[/code]

代码

UserMapper.xml
[code]
SELECT LAST_INSERT_ID() INSERT INTO users.user (username,birthday,sex,address)values (#{username},#{birthday},#{sex},#{address}) delete from users.user where id=#{id} update users.user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
[/code]

mapper 文件夹下的 UserMapper (注意:该名字要和xml同名要不然找不到)

image-20231220205846219
[code]
package mapper;import po.User;import java.util.List;public interface UserMapper { //根据id查询用户信息 public User findUserById(int id) throws Exception; //根据用户名列查询用户列表 public List 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;}
[/code]

Test类
[code]
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是在执行本类所有测试方法之前先调用这个方法 @Before public void setup() throws Exception{ //创建SqlSessionFactory String resource=”SqlMapConfig.xml”; //将配置文件加载成流 InputStream inputStream = Resources.getResourceAsStream(resource); //创建会话工厂,传入mybatis配置文件的信息 sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream); } @Test public void testFindUserById() throws Exception{ SqlSession sqlSession=sqlSessionFactory.openSession(); //创建UserMapper代理对象 UserMapper userMapper=sqlSession.getMapper(UserMapper.class); //调用userMapper的方法 User user=userMapper.findUserById(1); System.out.println(user.getUsername()); }}
[/code]

一些问题

  • 代理对象内部调用selectOneselectList
    • 如果mapper方法返回单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库。
    • 如果mapper方法返回集合对象,代理对象内部通过selectList查询数据库。
  • mapper接口方法参数只能有一个是否影响系统开发

mapper接口方法参数只能有一个,系统是否不利于扩展维护?系统框架中,dao层的代码是被业务层公用的。即使mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求。

注意:持久层方法的参数可以包装类型、map…等,service方法中建议不要使用包装类型(不利于业务层的可扩展)。

  • 在使用mybatis的selectList方法时,如果数据库的东西没东西返回,则不会为null 而是为空,而selectOne方法则会返回null

总结:数据库表字段如果有唯一约束,在mybatis中使用selectOne方法;
数据库表字段如果没有唯一约束,即使在业务逻辑上此字段时唯一的,但还是建议使用selectList方法。
如果数据库字段有唯一约束,那么你再添加相同的数据,则无法添加成功,但如果没有唯一约束,程序上可能出现并发,添加到数据库可以成功,但再次查询时会因为返回多条数据而导致程序出现问题。