mybatis学习2

Posted escapist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis学习2相关的知识,希望对你有一定的参考价值。

Mybatis解决jdbc编程的问题

1. 数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。

         解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库链接。

2. Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。

        解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。

3. 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。

       解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。

4. 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。

      解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。

 

mybatis与hibernate不同

Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。mybatis可以通过XML或注解方式灵活配置要运行的sql语句,

并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。

 

Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件

企业运营类软件等, 因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据

库的软件则需要自定义多套sql映射文件,工作量大。

 

Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。

但是Hibernate的学习门槛高, 要精通门槛更高, 而且怎么设计O/R映射,在性能和对象模型之间如何权衡, 以及怎样用好Hibernate需要具有很强的经验和能力才行。

总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。

 

Dao开发方法

使用MyBatis开发Dao,通常有两个方法,即原始Dao开发方法和Mapper动态代理开发方法。

原始Dao问题 每次都要创建session  里面 命名空间重复

原始Dao开发方式

原始Dao开发方法需要程序员自己编写Dao接口和Dao实现类。

public class UserDaoImpl implements UserDao {
    private SqlSessionFactory sqlSessionFactory;
    public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {this.sqlSessionFactory = sqlSessionFactory;
    }
    @Override
    public User queryUserById(int id) {
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
        User user = sqlSession.selectOne("queryUserById", id);
        sqlSession.close();
        return user;
    }
    @Override
    public List<User> queryUserByUsername(String username) {
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
        List<User> list = sqlSession.selectList("queryUserByUsername", username);
        sqlSession.close();
        return list;
    }
    @Override
    public void saveUser(User user) {
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
        sqlSession.insert("saveUser", user);
        sqlSession.commit();
        sqlSession.close();
    }
}
public class UserDaoTest {
    private SqlSessionFactory sqlSessionFactory;
    @Test
    public void testQueryUserByUsername() {
        UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
        List<User> list = userDao.queryUserByUsername("张");
        for (User user : list) {
            System.out.println(user);
        }
    }

    @Test
    public void testSaveUser() {
        UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
        User user = new User();
        user.setUsername("刘备");
        user.setBirthday(new Date());
        user.setSex("1");
        user.setAddress("蜀国");
        userDao.saveUser(user);
        System.out.println(user);
    }
}

原始Dao开发中存在以下问题:

1. Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法

2. 调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不得于开发维护。

 

Mapper动态代理方式

Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法

Mapper接口开发需要遵循以下规范:

1.  Mapper.xml文件中的namespace与mapper接口的类路径相同。

2.  Mapper接口方法名和Mapper.xml中定义的每个statement的id相同

3.  Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同

4.  Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

没有实现类  只有动态代理接口   注意这是Mybatis 提供的功能

遵循原则

  1. 接口 方法名 = User.xml id的名字(就是功能的方法)
  2. 返回值类型  与  Mapper.xml文件中返回值类型要一致
  3. 方法的入参类型 与Mapper.xml中入参的类型要一致

命名空间 绑定此接口  namespace 通常是接口全名

<?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">
<!-- namespace:命名空间,用于隔离sql -->
<!-- 还有一个很重要的作用,使用动态代理开发DAO,1. namespace必须和Mapper接口类路径一致 -->
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
    <!-- 根据用户id查询用户 -->
    <!-- 2. id必须和Mapper接口方法名一致 -->
    <!-- 3. parameterType必须和接口方法参数类型一致 -->
    <!-- 4. resultType必须和接口方法返回值类型一致 -->
    <select id="queryUserById" parameterType="int"
        resultType="cn.itcast.mybatis.pojo.User">
        select * from user where id = #{id}
    </select>

    <!-- 保存用户 -->
    <insert id="saveUser" parameterType="cn.itcast.mybatis.pojo.User">
        <selectKey keyProperty="id" keyColumn="id" order="AFTER"
            resultType="int">
            select last_insert_id()
        </selectKey>
        insert into user(username,birthday,sex,address) values
        (#{username},#{birthday},#{sex},#{address});
    </insert>
</mapper>

Dao接口  UserMapper

public interface UserMapper {
    User queryUserById(int id);
    List<User> queryUserByUsername(String username);
    void saveUser(User user);
}

加载UserMapper.xml文件

<!-- 加载映射文件 -->
    <mappers>
        <mapper resource="sqlmap/User.xml" />
        <mapper resource="mapper/UserMapper.xml" />
    </mappers>
public class UserMapperTest {
    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void init() throws Exception {
        // 创建SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 加载SqlMapConfig.xml配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 创建SqlsessionFactory
        this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
    }

    @Test
    public void testQueryUserById() {
        // 获取sqlSession,和spring整合后由spring管理
        SqlSession sqlSession = this.sqlSessionFactory.openSession();

        // 从sqlSession中获取Mapper接口的代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 执行查询方法
        User user = userMapper.queryUserById(1);
        System.out.println(user);

        // 和spring整合后由spring管理
        sqlSession.close();
    }

    @Test
    public void testQueryUserByUsername() {
        // 获取sqlSession,和spring整合后由spring管理
        SqlSession sqlSession = this.sqlSessionFactory.openSession();

        // 从sqlSession中获取Mapper接口的代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 执行查询方法
        List<User> list = userMapper.queryUserByUsername("张");
        for (User user : list) {
            System.out.println(user);
        }
        // 和spring整合后由spring管理
        sqlSession.close();
    }

    @Test
    public void testSaveUser() {
        // 获取sqlSession,和spring整合后由spring管理
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
        // 从sqlSession中获取Mapper接口的代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 创建保存对象
        User user = new User();
        user.setUsername("刘备");
        user.setBirthday(new Date());
        user.setSex("1");
        user.setAddress("蜀国");
        // 执行查询方法
        userMapper.saveUser(user);
        System.out.println(user);

        // 和spring整合后由spring管理
        sqlSession.commit();
        sqlSession.close();
    }
}

 

API的学习

SqlSession的使用

SqlSession中封装了对数据库的操作如:增删改查

SqlSession通过SqlSessionFactory创建。

SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。

 

SqlSessionFactoryBuilder

SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory

创建的。所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。

 

SqlSessionFactory

SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,

通常以单例模式管理SqlSessionFactory。

 

SqlSession

SqlSession是一个面向用户的接口,sqlSession中定义了数据库操作方法。

每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。

绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。

 

打开一个 SqlSession,使用完毕就要关闭它,通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。

SqlSession session = sqlSessionFactory.openSession();
try {
     // do work
} finally {
    session.close();
}

 

小结:

动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,

如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。

 

mybatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,输入

参数可以使用pojo包装对象或map对象,保证dao的通用性。  findUserById(PojoVo vo)

 

SqlMapConfig.xml配置文件

配置的内容和顺序如下

 

以上是关于mybatis学习2的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis 学习笔记总结

markdown [mybatis参考]关于mybatis #mybatis的一些片段

MyBatis-05-笔记

Mybatis学习笔记:动态SQL

MyBatis高级特性

[mybatis]动态sql_sql_抽取可重用的sql片段