mybatis学习进阶

Posted fzywhy

tags:

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

11、mybatis和hibernate本质区别和应用场景

1、hibernate:是一个标准的ORM(对象关系映射),不需要程序员写sql,sql语句自动生成

       :对sql语句进行优化,修改困难

适应于需求变化不多的中小型项目,egg:后台管理系统,ERP(enterprise resource planning)ORM(object,relational,Mapping),OA(office automation )system办公自动化,无纸化办公模式。

2、mybatis:专注的是sql,需要程序员编写sql语句,sql优化修改,优化方便

(不完全的ORM框架,可以实现映射(输入映射、输出映射))

       适用于需求变化比较多的项目,敏捷式开发(egg:互联网项目)

3、企业技术选型:低成本,高回报作为技术选型的原则,根据项目组的技术力量进行选择。

 

12、mybatis开发dao的方法

       1、SqlSession的使用范围:

 

SqlSessionFactoryBuilder:将其当成一个工具类使用即可,在需要创建SqlSessionFactory时,只需要new一次SqlSessionFactoryBuilder即可

SqlSessionFactory:使用单例模式管理sqlSessionFactory(工厂一旦创建,使用一个实例)

 

SqlSession:是一个面向用户(程序员)的接口,提供了很多操作数据库的方法

       selectOne:

       selectList:(返回单个或多个对象)

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

 

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

      

2、原始dao开发方法(程序员写dao接口和dao实现类)

手写dao接口和dao实现类

需要向dao实现类中注入SqlSessionFactory,在方法体通过SqlSessionFactory创建SqlSession

              dao接口:

public interface UserDao {

 

    //根据userId查询用户信息

    public User findUserById(int userId) throws Exception;

   

    //添加用户信息

    public void insertUser(User user) throws Exception;

   

    //删除用户信息

    public void deleteUser(int userId) throws Exception;

}

 

              dao

public class UserDaoImpl implements UserDao {

 

    //需要向dao实现类中注入SqlSessionFactory

    //这里通过构造方法注入

    private SqlSessionFactory sqlSessionFactory;

    public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {

        this.sqlSessionFactory = sqlSessionFactory;

    }

   

   

    @Override

    public User findUserById(int userId) throws Exception {

        SqlSession sqlSession = sqlSessionFactory.openSession();

        User user = sqlSession.selectOne("test.findUserById", userId);

        sqlSession.close();

        return user;

    }

 

    @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 userId) throws Exception {

        SqlSession sqlSession = sqlSessionFactory.openSession();

        sqlSession.delete("test.deleteUser", userId);

        sqlSession.commit();

        sqlSession.close();

       

    }

 

}

 

              单元测试:

public class UserDaoImplTest {

 

    private SqlSessionFactory sqlSessionFactory;

    //此方法是在执行testFindUserById之前执行

    @Before

    public void setUp() throws Exception {

        //创建sqlSessionFactory

        String resource = "SqlMapConfig.xml";

        InputStream config = Resources.getResourceAsStream(resource);

        sqlSessionFactory = new SqlSessionFactoryBuilder()

               .build(config);

    }

    @Test

    public void testFindUserById() throws Exception {

        //创建UserDao的对象

        System.out.println("ddddd:"+sqlSessionFactory);

        UserDao userDao = new UserDaoImpl(sqlSessionFactory);

        //调用UserDao的方法

       

        User user = userDao.findUserById(4);

       

        System.out.println(user);

    }

 

}

原始dao的开发问题:

       1、dao接口实现类方法中存在大量模板方法,(提取公共代码)

       2、调用sqlSession方法时将statement的userId硬编码了

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

3、mapper代理方法(程序员只需要写mapper接口)相当于dao接口

思路:           (mapper代理开发规范)

       1、编写mapper.xml映射文件

       2、编写mapper接口(相当于dao接口),需要遵循一些开发规范,mybatis可以自动生成mapper接口实现类代理对象。

开发规范:

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

<!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离

注意:使用mapper代理方法开发,namespace有特殊重要的作用

-->

<mapper namespace="com.fzy.mybatis.mapper.UserMapper">

       *mapper.java接口中的方法名和mapper.xml中statement的id一致

       *mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致

       *mapper.java接口中的方法返回值类型和mappe.xml中的resultType指定的类型一致。

public User findUserById(int id) throws Exception;

 

开发规范主要时对相似代码进行统一生成

 

       测试 :

mapper.java

 

public interface UserMapper {

 

    public User findUserById(int userId) throws Exception;

mapper.xml

 

<select id="findUserById" parameterType="int" resultType="com.fzy.mybatis.po.User">

        select * from users where userId = #{userId}

</select>

 

在SqlMapConfig.xml中配置加载mapper.xml

<mapper resource="mapper/UserMapper.xml"/>

 

测试代码:

public class UserMapperTest {

 

    private SqlSessionFactory sqlSessionFactory;

    //此方法时在执行testFindUserById之前执行

   

    @Before

    public void setUp() throws Exception {

        //创建sqlSessionFactory

        String resource = "SqlMapConfig.xml";

        InputStream inputStream = Resources.getResourceAsStream(resource);

        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    }

 

    @Test

    public void testFindUserById() throws Exception {

        SqlSession sqlSession = sqlSessionFactory.openSession();

        System.out.println("sqlSession:"+sqlSession);

        //创建UserMapper的代理对象

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        System.out.println("userMapper:"+userMapper);

        //调用UserMapper的方法

        User user = userMapper.findUserById(4);

       

        System.out.println(user);

    }

 

}

 

问题总结:

1、代理对象内部调用selectOne和selectList

       如果mapper方法返回单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库

       若mapper方法返回集合对象,代理对象内部通过selectList查询数据库

2、mapper接口方法参数只能有一个是否影响系统开发

      

       系统框架中,dao层的代码时被业务层公用的

即使mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求。

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

 

 

 

13、mybatis的全局配置文件

配置内容:

       properties(属性)

       settings(全局配置参数)

       typeAliases(类型别名)

typeHandlers(类型处理器)

objectFactory(对象工厂)

plugins(插件)

environments(环境集合属性对象)

       enviroument(环境子属性对象)

              transactionManager(事务管理)

              dataSource(数据源)

mappers(映射器)

       1、properties

将数据库连接参数单独配置在db.properties中,只需要在SqlMapConfig.xm中加载db.properties的属性值(解决数据库连接参数硬编码)

       将数据库连接参数只配置在db.properties中

jdbc.driver = com.mysql.jdbc.Driver

jdbc.url = jdbc:mysql://localhost:3306/travel?characterEncoding=utf-8

jdbc.username = root

jdbc.password = 123456

原因:方便对参数进行统一管理,其他的xml文件可以引用该db.properties

<!-- 加载属性文件 -->

    <properties resource="db.properties">

        <!-- properties中还可以配置一些属性名和属性值 -->

        <!-- <property name="" value=""/> -->

    </properties>

   

   

    <!-- 和spring整合后environments配置將移除 -->

    <environments default="development">

        <environment id="development">

            <!-- 使用jdbc事物管理,事物控制由mybatis進行 -->

           <transactionManager type="JDBC" />

           <!-- 数据库连接池,由mybatis管理 -->

           <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>

    <!-- 加载映射文件 -->

    <mappers>

        <mapper resource="sqlmap/User.xml"/>

        <!-- <mapper class="com.fzy.mybatis.mapper.UserMapper"/> -->

        <mapper resource="mapper/UserMapper.xml"/>

       

    </mappers>

注:mybatis加载属性的顺序

       1、在properties元素体内定义的属性首先被读取

       2、其后会读取properties元素中resource或url加载的属性,它会覆盖已读取的同名属性

       3、最后读取parameterType传递的属性,它会覆盖已读取的同名属性

so:parameterType传递的属性具有最高优先级,其次是properties中的resource或url,之后是properties元素体内定义的属性。

 

       不要在propeties元素体内添加任何属性值,只将属性值定义在properties文件中,在properties文件中定义属性名要有一定的特殊性,egg:xxx.xxx.xxx

 

       2、settings全局参数配置(需要时再设置)

mybatis框架在运行时可以调整一些运行参数:egg:开启二级缓存,开启延迟加载…

全局参数会影响mybatis的运行行为

       3、typeAliases(别名)常用

在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型,需要resultType指定输出结果的映射类型

       可以针对parameterType和resultType指定的类型定义一些别名,方便开发。

默认别名:

 

自定义别名:

<!-- 别名定义 -->

    <typeAliases>

        <!-- 针对单个别名的定义

        type:类型的路径

        alias:别名 -->

        <typeAlias type="com.fzy.mybatis.po.User" alias="user"/>

</typeAliases>

 

<!-- 批量别名定义

        指定包名,mybatis自动扫描包中的po类,自动定义别名,别名就是类名(首字母大小写均可)

         -->

        <package name="com.fzy.mybatis.po"/>

 

       4、typeHandlers类型处理器

mybatis中通过typeHandlers完成jdbc类型和Java类型的转换

       通常情况下,mybatis提供的类型处理器满足日常需要,不需要自定义

       5、mappers(映射配置)

加载单个映射文件(通过resource或url)

       <!-- 加载映射文件 -->

    <mappers>

        <!-- 通过resource方法一次加载一个映射文件 -->

        <mapper resource="sqlmap/User.xml"/>

        <!-- <mapper class="com.fzy.mybatis.mapper.UserMapper"/> -->

        <mapper resource="mapper/UserMapper.xml"/>

    </mappers>

通过mapper接口加载单个mapper

<!-- 通过mapper接口加载映射文件

        规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录中。

        前提:使用的是mapper代理方法

         -->

         <mapper class="com.fzy.mybatis.mapper.UserMapper"/>

根据规范:将mapper.java和mapper.xml放在一个目录中,且同名

 

批量加载mapper(推荐使用)

<!-- 批量加载mapper

         指定mapper接口的包名,mybatis自动扫描包下边所有的mapper接口进行加载

         规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录中。

         前提:使用的是mapper代理方法

          -->

          <package name="com.fzy.mybatis.mapper"/>

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

20160526-20160531mybatis入门进阶

MyBatis进阶使用——动态SQL

Java进阶 - MyBatis查询数据库 && Spring Boot 单元测试 - 细节狂魔

MyBatis案例 | 使用映射配置文件实现CRUD操作——动态SQL优化条件查询

90天Java---mybatis与mybatis plus-1

mybatis源码阅读-helloword