Mybatis

Posted miantiao312

tags:

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

Dao开发方法

使用Mybatis开发Dao,通常有两个方法,即原始Dao开发方法和Mapper接口开发方法。

先介绍几个概念

a、SqlSession的使用范围

   SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。
   通过SqlSessionFactory创建SqlSession,而SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建

b、SqlSessionFactoryBuilder

   SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不  
   需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory生产,所以可  
   以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。

c、SqlSessionFactory

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

d、SqlSession

    SqlSession是一个面向用户的接口, sqlSession中定义了数据库操作方法。每个线程都应该有它自己的  
    SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法  
    范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。打开一个 SqlSession,  
    使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭

1、原始Dao开发方式:原始Dao开发方法需要程序员编写Dao接口和Dao实现类。

 需求:根据用户id查询一个用户信息
      根据用户名称模糊查询用户信息列表
      添加用户信息

Dao接口和实现

接口

    public interface UserDao {

        User getUserById(int id);
        List<User> getUserByUsername(String username);
        void insertUser(User user);
    }

实现

    public class UserDaoImpl implements UserDao {

        //注入SqlSessionFactory
        private SqlSessionFactory sqlSessionFactory;
        
        public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
            this.sqlSessionFactory = sqlSessionFactory;
        }

        @Override
        public User getUserById(int id) {
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 根据id查询用户信息
            User user = sqlSession.selectOne("getUserById", id);
            // 关闭SQLSession
            sqlSession.close();
            return user;
        }

        @Override
        public List<User> getUserByUsername(String username) {
            // 创建一个SQLSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 执行查询
            List<User> list = sqlSession.selectList("getUserByUsername", username);
            // 释放资源
            sqlSession.close();
            return list;
        }

        @Override
        public void insertUser(User user) {
            // 创建一个SQLSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 插入用户
            sqlSession.insert("insertUser", user);
            // 提交事务
            sqlSession.commit();
            // 释放资源
            sqlSession.close();
        }

测试

    public class UserDaoImplTest {

        //创建会话工厂
        private SqlSessionFactory sqlSessionFactory = null;
        
        @Before
        public void createSqlSessionFactory() throws Exception {
            //第一步:创建一个SQLSessionFactoryBuilder对象。
            SqlSessionFactoryBuilder sessionFactoryBuilder=new SqlSessionFactoryBuilder();
            //第二步:加载配置文件。
            InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
            //第三步:创建SQLSessionFactory对象
            sqlSessionFactory = sessionFactoryBuilder.build(inputStream);
        }
    
    
        @Test   //根据用户id获取用户
        public void getUserByIdTest() {
            UserDao userDao = new UserDaoImpl(sqlSessionFactory);
            User user = userDao.getUserById(10);
            System.out.println(user);
        }
        
        @Test   //通过用户名查询用户
        public void findUserByUsernameTest() {
            UserDao userDao = new UserDaoImpl(sqlSessionFactory);
            List<User> list = userDao.getUserByUsername("张");
            for (User user : list) {
                System.out.println(user);
            }
        }

        @Test
        public void insertUserTest() {
            UserDao userDao = new UserDaoImpl(sqlSessionFactory);
            User user = new User();
            user.setUsername("赵云");
            user.setAddress("正定");
            user.setBirthday(new Date());
            user.setSex("1");
            userDao.insertUser(user);
        }
  }

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

Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作  
方法调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不得于开发维护。

2、Mapper动态代理方式

Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义  
创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
    Mapper接口开发需要遵循以下规范:
    a、Mapper.xml文件中的namespace与mapper接口的类路径相同。
    b、Mapper接口方法名和Mapper.xml中定义的每个statement的id相同 
    c、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
    d、Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

创建包 com.kid.mybatis.mapper

    a、接口:UserMapper
        public interface UserMapper {
            User getUserById(int id);
            List<User> getUserByUsername(String username);
            void insertUser(User user);
        }

    b、映射文件:UserMapper.xml
        <?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语句的隔离,
             #{}作用就是占位符,相当于jdbc的“?”
             parameterType:查询的参数类型
                定义输入到sql中的映射类型,#{id}表示使用preparedstatement设置占位符号并将输入变量id传到sql。
             resultType:查询结果的数据类型,如果是pojo应该给全路径。
        -->
        <!-- mapper代理的开发规则:
                1、namespace必须时候接口的全限定名
                2、Statementid必须和接口的方法名称一致
                3、接口方法的参数类型要和parameterType要一致
                4、接口方法的返回值类型要和resultType一致
         --> 
        <mapper namespace="com.kid.mybatis.mapper.UserMapper">
            <!-- 通过用户id获取用户 -->
            <select id="getUserById" parameterType="int" resultType="user">
                select * from user where id = #{id}
            </select>
            
            <!-- 如果查询结果返回list, resultType设置为list中一个元素的数据类型
                ${}字符串拼接指令
            -->
            <select id="getUserByUsername" parameterType="string" resultType="user">
                <!-- ${value}表示使用参数将${value}替换,做字符串的拼接。
                      注意:如果是取简单数量类型的参数,括号中的值必须为value
                 -->
                select * from user where username like ‘%${value}%‘
            </select>
            
            <!-- 参数时候pojo时,#{}中的名称就是pojo的属性 -->
            <insert id="insertUser" parameterType="user">
                <!-- keyProperty:对于pojo的主键属性 
                    resultType:对应主键的数据类型
                    order:是在insert语句执行之前或者之后。
                    如果使用uuid做主键,应该先生成主键然后插入数据,此时应该使用Before
                 -->
                <selectKey keyProperty="id" order="AFTER" resultType="int">
                    select LAST_INSERT_ID()
                </selectKey>
                
                    insert into user(username,birthday,sex,address) 
                    value(#{username},#{birthday},#{sex},#{address})
            </insert>
        </mapper>

    c、改造SqlMapperConfig.xml
        <?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
        
        <configuration>
            <!-- 配置属性 先加载内部属性,再加载外部属性,如果有同名属性会覆盖-->
            <properties resource="db.properties"/>
                    
            <!-- 配置pojo别名 -->
            <typeAliases>
                <!-- 扫描包的形式创建别名,别名就是类名,不区分大小写 -->
                <package name="com.kid.mybatis.pojo"/>
            </typeAliases>
            
            <!-- 和spring整合后 environments配置将废除-->
            <environments default="development">
                <environment id="development">
                <!-- 使用jdbc事务管理-->
                    <transactionManager type="JDBC" />
                <!-- 数据库连接池-->
                    <dataSource type="POOLED">
                        <property name="driver" value="${jdbc.driver}" />
                        <property name="url" value="${jdbc.url}" />
                        <property name="username" value="${jdbc.username}" />
                        <property name="password" value="${jdbc.password}" />
                    </dataSource>
                </environment>
            </environments>
            
            <!-- 加载mapper文件 -->
            <mappers>
                <!-- resource基于classpath查找 -->
                <mapper resource="sqlmap/user.xml"/>
                <!-- 根据接口名称加载mapper文件
                    要求:1、mapper映射文件和接口在同一个目录下
                        2、mapper映射文件的名称和接口名称一致。
                        3、class就是接口的权限定名
                 -->
                <!-- 使用扫描包的形式加载mapper文件 -->
                <package name="com.kid.mybatis.mapper"/>
            </mappers>
        </configuration>
        

测试用例

    public class UserMapperTest {
    
            private SqlSessionFactory sqlSessionFactory = null;
        
            @Before
            public void init() throws Exception {
                // 第一步:创建一个SQLSessionFactoryBuilder对象。
                SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
                // 第二步:加载配置文件。
                InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
                // 第三步:创建SQLSessionFactory对象
                sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
            }
            
            
            @Test   //根据用户id获取用户
            public void getUserByIdTest() {
                //和spring整合后省略
                SqlSession sqlSession = sqlSessionFactory.openSession();
                //获取代理对象
                UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
                User user = userMapper.getUserById(10);
                System.out.println(user);
                
                //和spring整合后省略
                sqlSession.close();
            }
            
            @Test   //通过用户名查询用户
            public void findUserByUsernameTest() {
                SqlSession sqlSession = sqlSessionFactory.openSession();
                UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
                List<User> list = userMapper.getUserByUsername("张");
                for (User user : list) {
                    System.out.println(user);
                }
                sqlSession.close();
            }
            
            @Test
            public void insertUserTest() {
                SqlSession sqlSession = sqlSessionFactory.openSession();
                UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
                User user = new User();
                user.setUsername("关羽");
                user.setAddress("硅谷");
                user.setBirthday(new Date());
                user.setSex("2");
                userMapper.insertUser(user);
                sqlSession.commit();
                sqlSession.close();
            }
    }

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

SSM-MyBatis-05:Mybatis中别名,sql片段和模糊查询加getMapper

mybatis动态sql片段与分页,排序,传参的使用

MyBatis动态SQL标签用法

MYBATIS05_ifwherechoosewhentrimsetforEach标签sql片段

mybatis动态sql之利用sql标签抽取可重用的sql片段

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