【Mybatis】 02 - Mybatis 进阶

1. 知识回顾

1.1 回顾自定义Mybatis流程分析

自定义mybatis开发流程图

1.2 回顾Mybatis环境搭建-以及实现查询所有的功能

  1. 创建一个maven 工程 ,不使用骨架 。直接选择maven之后点击next即可:
创建一个maven工程 不使用骨架
  1. 填写自己的groupId(域名反写) 和 ArtifactId (项目名称);

  2. 设置项目的打包方式为 jar ;

jar
  1. 导入依赖 ,Mybatis 依赖 、MySql驱动依赖、log4j依赖、junit单元测试依赖;

        
            org.mybatis
            mybatis
            3.4.5
        

        
            mysql
            mysql-connector-java
            5.1.6
        

        
            log4j
            log4j
            1.2.17
        

        
            junit
            junit
            4.13
        
    
  1. 编写User实体类 并实现 Serializable 序列化接口
/**
 * User实体类
 */
public class User  implements Serializable{
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
  // 省略setter 和 getter 方法 
  // 省略 toString方法
}
  1. 编写 UserDao 持久层接口

public interface UserDao {
    /**
     * 查询所有用户信息
     * @return
     */
    List findAll();
}
  1. 在resources 目录下创建 SqlMapConfig.xml全局配置文件 并 导入相关约束
    在resources目录下创建SqlMapConfig.xml文件


  1. 在SqlMapConfig.xml文件中配置相关属性



    
    
        
        
            
            
            
            
                
                
                
                
            
        
    

  
    
        
    

  1. 在 resources 目录下创建 与 UserDao.java 持久层接口目录相同的UserDao.xml映射配置文件;



    

  1. 编写测试类
/**
 * mybatis回顾 测试类
 */
public class MybatisLookBackTest {
    @Test
    public void testSelectList() throws IOException {
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        SqlSession session = factory.openSession();
        UserDao userDao = session.getMapper(UserDao.class);
        List users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
        }
        session.close();
    }
}

2. Mybatis的CRUD操作

2.1 Mybatis的CRUD 之 保存(在上面回顾代码的项目基础上)

  1. 在UserDao 持久层接口中编写 保存用户信息的方法 saveUser(User user);
 void saveUser(User user);
  1. 在UserDao.xml映射配置文件中编写对应的 insert 标签 使用 parameterType 指定参数类型, 并编写 sql 语句
    
        insert into user (username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
    
#{} 括号中的属性来自setter 和 getter 方法
  1. 在测试类中编写对应的测试方法 : 方法中已经将 获取UserDao代理对象的代码抽取到了 测试方法执行之前的方法中。
@Test
    public void testSaveUser() {
        User user = new User();
        user.setUsername("王晓华");
        user.setBirthday(new Date());
        // 注意这里的字符个数应该与数据库对应
        user.setSex("男");
        user.setAddress("重庆市巴南区");
        // 抽取 获取userDao代理对象的过程 到 测试方法执行之前 , 将释放资源的代码统一写到测试方法执行之后
        userDao.saveUser(user);
    }
  1. 抽取获取UserDao代理对象代码 :

  // 在测试类中定义如下属性(成员变量) 
    private InputStream in;
    private UserDao userDao;
    private SqlSession sqlSession;

  // 测试类中定义如下方法 

    /**
     * @Before 在测试方法执行之前执行
     */
    @Before
    public void init() throws IOException {
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        sqlSession = factory.openSession();
        userDao = sqlSession.getMapper(UserDao.class);
    }

    /**
     * @After 在测试方法执行之后执行
     */
    @After
    public void destroy() {
        // 需要提交事务
        // sqlSession.commit();

        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (sqlSession != null) {
            sqlSession.close();
        }
    }

  1. 需要注意的是,这里需要手动提交事务:
未进行事务的提交,事务将会回滚
  1. 在测试方法执行之后释放资源之前进行事务的提交即可 :
在测试方法执行完成之后 ,释放资源之前 ,进行事务的提交

2.2 MyBatis CRUD 之 修改 和 删除

2.2.1 修改操作

  1. 在UserDao持久层接口中编写修改方法
// 在UserDao 持久层接口中编写修改方法 
 /**
     * 更新用户信息
     * @param user
     */
    void updateUser(User user);
  1. 在UserDao.xml映射配置文件中使用update标签 并使用parameterType属性指定参数类型。编写更新的sql
    
        update user set username = #{username} , birthday = #{birthday} , sex = #{sex} ,
        address = #{address} where id = #{id}
    
  1. 在测试类中编写测试方法测试更新操作,更新操作也是需要进行手动提交事务操作
     /**
     * 修改
     */
    @Test
    public void testUpdateUser() {
        User user = new User();
        user.setId(50);
        user.setUsername("mybatis update");
        user.setBirthday(new Date());
        user.setAddress("重庆市渝北区");
        user.setSex("女");
        userDao.updateUser(user);
    }

2.2.2 删除操作

  1. 在UserDao持久层接口中编写删除方法
   /**
     * 删除用户信息
     * @param userId
     */
    void deleteUser(int userId) ;
  1. 在UserDao.xml映射配置文件中使用delete标签编写sql语句,并使用parameterType设置传递的参数类型这里的 parameterType 的值可以为 int 、 INT 、INTEGER 、 Integer、java.lang.Integer。sql语句 : id = #{由于传递的参数只有一个,所以这里的名称可以随意}
  
    
    
        delete from user where id = #{uid}
    
  1. 在测试类中编写测试方法进行删除测试
    /**
     * 删除
     */
    @Test
    public void testDeleteUser() {
        userDao.deleteUser(51);
    }

2.3 查询一个和模糊查询

2.3.1 查询一个 (根据id查询一个)

  1. 在UserDao持久层接口中编写方法。
 /**
     * 根据id查询用户信息
     * @param userId
     * @return
     */
    User selectById(int userId);
  1. 在UserDao.xml映射配置文件中使用select标签,并使用parameterType 执行参数类型 , 使用resultType='返回值全限定类名'指定返回值类型

    
  1. 在测试类中编写测试方法进行测试
   /**
     * 根据id查询用户信息
     */
    @Test
    public void testSelectById() {
        User user = userDao.selectById(50);
        System.out.println(user);
    }

2.3.2 根据用户名进行模糊查询

  1. 在UserDao持久层接口中编写进行模糊查询的方法
     /**
     * 根据用户名进行模糊查询
     * @param username
     * @return
     */
    List selectByUsername(String username);
  1. 在UserDao.xml映射配置文件中使用select标签,并使用parameterType 执行参数类型 , 使用resultType='返回值全限定类名'指定返回值类型
 
    
    
  1. 在测试类中编写测试方法
    /**
     * 根据username进行模糊查询
     */
    @Test
    public void testSelectByUsername() {
        List users = userDao.selectByUsername("%王%");
        for (User user : users) {
            System.out.println(user);
        }
    }

2.4 查询返回一行一列 和 占位符分析

2.4.1 查询返回数据总条数

  1. 在UserDao持久层接口中编写查询数据总条数的方法
   /**
     * 查询数据总条数
     * @return
     */
    int selectTotal();
  1. 在UserDao.xml映射配置文件中使用select标签 编写sql语句 ,并使用resultType='' 指定返回值类型
    
    
  1. 在测试类中编写测试方法进行测试
     /**
     * 查询数据总条数
     */
    @Test
    public void testSelectTotal() {
        int total = userDao.selectTotal();
        System.out.println("数据总条数: " + total);
    }

2.4.2 模糊查询占位符细节

  1. 可以使用 如下方式代替模糊查询传递参数时需要写上%%;

    
    
/**
     * 根据username进行模糊查询
     */
    @Test
    public void testSelectByUsername() {
        //List users = userDao.selectByUsername("%王%");
        List users = userDao.selectByUsername("王");
        for (User user : users) {
            System.out.println(user);
        }
    }
  1. 进行模糊查询时占位符细节分析:
进行模糊查询时占位符细节分析

2.4.3 保存操作的细节

  1. 保存的时候由于主键自增长的原因,我们是不知道保存时的id的。但是如果我们需要得到当前保存数据的id,可以通过以下的配置
-- 在数据库中插入一条数据并返回 此时插入数据的id
INSERT INTO USER(username,address,sex,birthday) VALUES('testId','重庆市','男','2020-08-30');
SELECT LAST_INSERT_ID();


        
        
            select LAST_INSERT_ID();
        
        insert into user (username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
    
保存数据后获取保存数据的id

3. MyBatis的参数深入

3.1 OGNL 表达式

  1. OGNL : Object Graphic Navigation Language 对象图导航语言;

  2. 作用 : 它是通过对象的取值方法来获取数据 。在写法上将get省略掉;

  3. 案例 : 在获取用户名称的时候 , 类中的写法 user.getUsername(); OGNL表达式的写法:user.username;

  4. Mybatis中为什么能直接写username,而不是user.username。因为在parameterType中已经提供了属性所属的类,所以此时不需要写对象名而直接写属性名称。

3.2 使用实体的包装对象作为查询条件

  1. 定义一个实体的包装类对象QueryVo作为查询条件
/**
 * 实体包装类对象 
 */
public class QueryVo {
    
    private User user;
    // 省略 setter 和 getter 方法 
}
  1. 在UserDao持久层接口中编写根据包装类对象进行查询的方法;
  1. 在UserDao.xml映射配置文件中使用select编写查询的语句 ,注意在占位符中写的参数
  
    
映射配置文件中属性对应
  1. 在测试类中编写方法进行测试
 /**
     * 根据包装类对象进行查询
     */
    @Test
    public void testSelectByVo() {
        User user = new User();
        user.setUsername("%王%");
        QueryVo vo = new QueryVo();
        vo.setUser(user);
        List users = userDao.selectByVo(vo);
        for (User u : users) {
            System.out.println(u);
        }
    }

3.3 实体类属性名称和数据库列名不一致

  1. 会出现报错的情况。 这时修改映射配置文件中的属性与实体类对应,增删改操作是可以使用的。但是注意查询操作的时候,将封装不进去了。

  2. 修改实体类的属性名称如下:

/**
 * User实体类
 */
public class User implements Serializable {

    private Integer userId;
    private String userName;
    private Date userBirthday;
    private String userSex;
    private String userAddress;

  // 省略setter 和 getter方法 
}
  1. 在修改映射配置文件中实体类属性之后,添加和修改操作恢复正常,但是查询操作就值得注意。因为返回的结果集将封装不上。但是userName列比较特殊可以封装上,这是因为在windows下MySQL数据库列名是不区分大小写的。但是在linux操作系统下的MySQL是严格区分大小写的。
值得注意的查询之后封装的结果集

3.4 解决实体类属性与数据库列名称不对应的问题

3.4.1 方式一 :起别名

  1. 通过起别名的方式使数据库列名与实体类属性对应上 。
 

3.4.2 方式二 : 采用配置的方式

  1. 使用resultMap标签,定义实体类属性与数据库列名之间的配置映射关系。
  
    
        
        
        
        
        
        
        
    
  1. 在 select 标签中 使用resultMap 属性设置使用的resultMap 。
 

3.5 案例地址

  1. 案例码云地址 : https://gitee.com/lpzzzz/mybatis_demo_-crud_04

4. 自定义Dao实现类

  1. 创建新项目 , 复制上面的项目将实体类属性改为与数据库列名一致,删除以封装对象作为查询条件的方法。

4.1 使用自定义实现类的方式 实现 查询所有

  1. 编写 UserDao接口的实现类 UserDaoImpl.java; 实现其所有的方法 , 并使用构造方法的方式初始化一个SqlSessionFactory对象;
public class UserDaoImpl implements UserDao {


    // 需要使用构造函数创建一个SqlSessionFactory 对象
    private SqlSessionFactory factory;

    public UserDaoImpl(SqlSessionFactory factory) {
        this.factory = factory;
    }

    /**
     * 查询所有
     *
     * @return
     */
    public List findAll() {
        // 获取一个sqlSession对象
        SqlSession session = factory.openSession();
        List users = session.selectList("com.lyp.dao.UserDao.findAll");
        session.close();
        return users;
    }

}
  1. 修改测试类中的配置
/**
 * mybatis回顾 测试类
 */
public class MybatisLookBackTest {

    private InputStream in;
    private UserDao userDao;


    /**
     * @Before 在测试方法执行之前执行
     */
    @Before
    public void init() throws IOException {
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        userDao = new UserDaoImpl(factory);
    }

  /**
     * @After 在测试方法执行之后执行
     */
    @After
    public void destroy() {
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 查询所有
     *
     * @throws IOException
     */
    @Test
    public void testSelectList() throws IOException {
        List users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
        }
    }
}

4.2 使用自定义实现类的方式 实现 保存数据

  1. 在UserDao实现类 UserDaoImpl 中实现 保存的的方法 saveUser。
     /**
     * 保存
     * @param user
     */
    public void saveUser(User user) {
        // 获取一个sqlSession对象
        SqlSession session = factory.openSession();
        session.insert("com.lyp.dao.UserDao.saveUser", user);
        session.commit();
    }

4.3 使用自定义实现类的方式 实现 修改数据

  1. 在UserDao实现类UserDaoImpl中实现 修改方法 updateUser。
    public void updateUser(User user) {
        // 获取一个sqlSession对象
        SqlSession session = factory.openSession();
        session.update("com.lyp.dao.UserDao.updateUser", user);
        session.commit();
    }

4.4 使用自定义实现类的方式 实现 删除数据

  1. 在UserDao实现类UserDaoImpl中实现 删除方法 deleteUser。
public void deleteUser(int userId) {
        // 获取一个sqlSession对象
        SqlSession session = factory.openSession();
        session.update("com.lyp.dao.UserDao.deleteUser", userId);
        session.commit();
    }

4.5 使用自定义实现类的方式 实现 根据id查询

  1. 在UserDao实现类UserDaoImpl中实现 查询一个(根据id查询)的方法 selectById。
/**
     * 查询一个(根据id进行查询)
     * @param userId
     * @return
     */
    public User selectById(int userId) {
        // 获取一个sqlSession对象
        SqlSession session = factory.openSession();
        User user = session.selectOne("com.lyp.dao.UserDao.selectById", userId);
        session.commit();
        return user;
    }

4.6 使用自定义实现类的方式 实现 根据用户名进行模糊查询

  1. 在UserDao实现类UserDaoImpl中实现 根据用户名进行模糊查询 的方法 selectByUsername。
 /**
     * 根据username进行模糊查询
     * @param username
     * @return
     */
    public List selectByUsername(String username) {
        // 获取一个sqlSession对象
        SqlSession session = factory.openSession();
        return session.selectList("com.lyp.dao.UserDao.selectByUsername",username);
    }

4.7 使用自定义实现类的方式 实现 查询数据条数

/**
     * 查询当前数据库中数据条数
     * @return
     */
    public int selectTotal() {
        // 获取一个sqlSession对象
        SqlSession session = factory.openSession();
        return session.selectOne("com.lyp.dao.UserDao.selectTotal");
    }

5. 使用Dao实现类方式的执行过程分析

非常重要的一张图-分析编写dao实现类Mybatis的执行过程

5.1 断点小技巧

断点小技巧
如何进入到实现类中

6. properties 标签的使用及细节

  1. 在使用代理dao的方式的项目 (mybatis_demo_CRUD_04) 中进行配置。

  2. 码云地址 : https://gitee.com/lpzzzz/mybatis_demo_-crud_04

6.1 在标签中直接配置数据库连接信息

  1. 将原来的数据库配置信息复制到 properties 标签中 ,然后使用${} 使用属性名称进行引用。
 
    
        
        
        
        
    



    
        
        
            
            
            
            
                
                
                
                
            
        
    
在properties标签中直接配置数据库连接信息

6.2 使用 properties配置文件的方式

  1. 先再类路径 resources 目录下创建 一个编写数据库配置信息的properties配置文件。内容如下:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=xxxx
  1. 在properties标签上使用,resource属性配置配置文件位置及名称 :

    
  1. 和标签内配置数据库连接信息一样,使用${} 获取到数据库的连接信息:
 
    
        
        
            
            
            
            
                
                
                
                
            
        
    

6.3 在引用properties 配置文件两种方式

6.3.1 使用resource 属性

  1. 使用resource属性是使用相对路径读取的类路径下的文件。

    
数据库信息配置文件放在了类路径下

6.3.2 使用 url 属性

  1. URL: Uniform Resource Locator 统一资源定位符,它是可以标识一个资源的位置;
  • 例: localhost:9999/user/userInfo?id=100
  1. URI: Uniform Resource Identifier 统一资源标识符,它是可以在应用中唯一定位一个资源的位置。
  • 例:/user/userInfo?id=100
  1. 在配置中使用 url 属性配置配置文件的位置:


    查看配置文件的绝对路径
   
    

  1. properties标签配置的位置:
properties标签配置的位置

7. TypeAliases 和 package 标签的使用

  1. 使用typeAliases 标签 中的typeAlias标签 配置 别名。只能配置domain中类的别名。type属性指定的是实体类的全限定类名,alias属性上指定的是别名,指定之后就不在区分大小写。
    
        
        
    
  1. 使用 typeAliases 标签 中的 packge 标签配置别名 , 用于指定要配置别名的包,当指定后,该包下的实体类都会注册别名并且类名就是别名,并且不在区分大小写。
   
        
        
    
  1. 在mappers 标签中也有一个package的标签。该标签是用于指定dao接口所在的包。当指定完成之后就不需要再写 mapper 以及 resource 和class了。
   
        
        
        
    
  1. 上面几个标签的使用如下图 :
以上几个标签的使用

你可能感兴趣的:(【Mybatis】 02 - Mybatis 进阶)