美文网首页
Mybatis----(1)

Mybatis----(1)

作者: 艾剪疏 | 来源:发表于2018-07-04 11:57 被阅读31次

    主要内容
    1、对原生态jdbc程序(单独使用jdbc开发)问题总结
    2、mybatis框架原理
    3、mybatis入门程序
    4、mybatis开发dao两种方法
    5、mybatis配置文件SqlMapConfig.xml
    6、mybatis核心
    7、mybatis的动态sql

    1、原生态jdbc程序中问题总结

    下面的代码,有很多问题,总结如下:

    public class JdbcTest {
        
        public static void main(String[] args) {
            
            //数据库连接
            Connection connection = null;
            //预编译的Statement,使用预编译的Statement提高数据库性能
            PreparedStatement preparedStatement = null;
            //结果 集
            ResultSet resultSet = null;
            
            try {
                //加载数据库驱动
                Class.forName("com.mysql.jdbc.Driver");
                
                //通过驱动管理类获取数据库链接
                connection =  DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "mysql");
                //定义sql语句 ?表示占位符
                String sql = "select * from user where username = ?";
                //获取预处理statement
                preparedStatement = connection.prepareStatement(sql);
                //设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
                preparedStatement.setString(1, "王五");
                //向数据库发出sql执行查询,查询出结果集
                resultSet =  preparedStatement.executeQuery();
                //遍历查询结果集
                while(resultSet.next()){
                    System.out.println(resultSet.getString("id")+"  "+resultSet.getString("username"));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                //释放资源
                if(resultSet!=null){
                    try {
                        resultSet.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                if(preparedStatement!=null){
                    try {
                        preparedStatement.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                if(connection!=null){
                    try {
                        connection.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
    
            }
    
    
        }
    }
    

    1、数据库连接,使用时就创建,不使用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响 数据库性能。
    设想:使用数据库连接池管理数据库连接。

    2、将sql语句硬编码到java代码中,如果sql 语句修改,需要重新编译java代码,不利于系统维护。
    设想:将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译。

    3、向preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在java代码中,不利于系统维护。
    设想:将sql语句及占位符号和参数全部配置在xml中。

    4、从resutSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,,不利于系统维护。
    设想:将查询的结果集,自动映射成java对象。

    2、mybatis框架

    2-1 mybatis是什么?

    mybatis是一个持久层的框架,是apache下的顶级项目。

    mybatis让程序将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活生成(半自动化,大部分需要程序员编写sql)满足需要sql语句。

    mybatis可以将向 preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射)

    2-2 mybatis框架

    image.png

    2-3 mybatis使用步骤(基础方式1)

    image.png

    1 读取SqlMapConfig.xml文件,其中配置了Mybatis的基本信息

    private SqlSessionFactory sqlSessionFactory;
    
        // 此方法是在执行testFindUserById之前执行
        @Before
        public void setUp() throws Exception {
            // 创建sqlSessionFactory
    
            // mybatis配置文件
            String resource = "SqlMapConfig.xml";
            // 得到配置文件流
            InputStream inputStream = Resources.getResourceAsStream(resource);
    
            // 创建会话工厂,传入mybatis的配置文件信息
            sqlSessionFactory = new SqlSessionFactoryBuilder()
                    .build(inputStream);
        }
    

    2 配置mybatis的运行环境,数据源、事务等。

    <configuration>
        <!-- 加载属性文件 -->
        <properties resource="db.properties">
            <!--properties中还可以配置一些属性名和属性值  -->
            <!-- <property name="jdbc.driver" 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"/>
        </mappers>
    
    </configuration>
    

    3 新建xml的sql对象

    <mapper namespace="test">
    
        <!--如果输入 参数是简单类型,#{}中的参数名可以任意,可以value或其它名称-->
        <select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">
            select * from user where id = #{value}
        </select>
    
        <!-- ${value}:接收输入 参数的内容,如果传入类型是简单类型,${}中只能使用value
         返回值是list还是单个值,通过接口的返回值确定
         -->
        <select id="findUserByName" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User">
            SELECT * FROM USER WHERE username LIKE '%${value}%'
        </select>
    
    
        <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
            <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
                SELECT LAST_INSERT_ID()
            </selectKey>
            insert into user(username,birthday,sex,address) value(#{username},#{birthday},#{sex},#{address})
       </insert>
    
    
        <delete id="deleteUser" parameterType="java.lang.Integer">
            delete from user where id=#{id}
        </delete>
    
    
        <update id="updateUser" parameterType="cn.itcast.mybatis.po.User">
            update user set sex=#{sex}
            where id=#{id}
        </update>
    
    </mapper>
    

    4 定义接口和实现类

    接口

    public interface UserDao {
    
        //根据id查询用户信息
        public User findUserById(int id) throws Exception;
    
        //根据用户名列查询用户列表
        public List<User> 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;
    }
    
    

    实现类

    // 需要向dao实现类中注入SqlSessionFactory
        // 这里通过构造方法注入
        private SqlSessionFactory sqlSessionFactory;
    
        public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
            this.sqlSessionFactory = sqlSessionFactory;
        }
    
    
        public User findUserById(int id) throws Exception {
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            User user = sqlSession.selectOne("test.findUserById", id);
    
            // 释放资源
            sqlSession.close();
    
            return user;
        }
    
        public List<User> findUserByName(String name) throws Exception {
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            List<User> list = sqlSession.selectList("test.findUserByName", name);
    
            // 释放资源
            sqlSession.close();
    
            return list;
        }
    
        public void insertUser(User user) throws Exception {
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            //执行插入操作
            sqlSession.insert("test.insertUser", user);
    
            // 提交事务
            sqlSession.commit();
    
            // 释放资源
            sqlSession.close();
        }
    
        public void deleteUser(int id) throws Exception {
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            //执行插入操作
            sqlSession.delete("test.deleteUser", id);
    
            // 提交事务
            sqlSession.commit();
    
            // 释放资源
            sqlSession.close();
        }
    
        public void updateUser(User user) throws Exception {
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            //执行插入操作
            sqlSession.update("test.updateUser", user);
    
            // 提交事务
            sqlSession.commit();
    
            // 释放资源
            sqlSession.close();
        }
    

    3 mybatis使用方式(2)---- mapper代理

    可以发现上述的接口实现类中存在大量的重复代码

    所以Mybatis还提供直接通过xml来执行的sql语句的方式

    1 测试类代码

     @Test
        public void findUserId() throws Exception{
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            //创建UserMapper对象,mybatis自动生成mapper代理对象
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    
            //调用userMapper的方法
            User user = userMapper.findUserId(1);
            
            System.out.println(user);
        }
    
    <mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
        <select id="findUserId" parameterType="int" resultType="cn.itcast.mybatis.po.User">
            select * from user where id=#{value}
        </select>
    </mapper>
    
    

    上面的测试类代码是可以直接通过匹配xml中的id调用xml的sql语句执行查询的
    User user = userMapper.findUserId(1);
    ,简化了实现类的书写。

    开发规范:

    1、在mapper.xml中namespace等于mapper接口地址
    2、mapper.java接口中的方法名和mapper.xml中statement的id一致
    3、mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致。
    4、mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致。

    总结:
    以上开发规范主要是对下边的代码进行统一生成:

    User user = sqlSession.selectOne("test.findUserById", id);
    sqlSession.insert("test.insertUser", user);

    4 SqlMapConfig.xml的配置

    mybatis的全局配置文件SqlMapConfig.xml,配置内容如下:

    properties(属性)
    settings(全局配置参数)
    typeAliases(类型别名)
    typeHandlers(类型处理器)
    objectFactory(对象工厂)
    plugins(插件)
    environments(环境集合属性对象)
    environment(环境子属性对象)
    transactionManager(事务管理)
    dataSource(数据源)
    mappers(映射器)

    4-1 properties属性

    可将数据库连接参数单独配置在db.properties中,只需要在SqlMapConfig.xml中加载db.properties的属性值。
    在SqlMapConfig.xml中就不需要对数据库连接参数硬编码。

    将数据库连接参数只配置在db.properties中,原因:方便对参数进行统一管理,其它xml可以引用该db.properties。

        <!-- 加载属性文件 -->
        <properties resource="db.properties">
            <!--properties中还可以配置一些属性名和属性值  -->
            <!-- <property name="jdbc.driver" value=""/> -->
        </properties>
    

    建议:
    不要在properties元素体内添加任何属性值,只将属性值定义在properties文件中。
    在properties文件中定义属性名要有一定的特殊性,如:XXXXX.XXXXX.XXXX

    4-2 settings全局参数配置

    mybatis框架在运行时可以调整一些运行参数。
    比如:开启二级缓存、开启延迟加载。。

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

    4-3 typeAliases(别名)重点

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

    如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。

    <!-- 别名定义 -->
        <typeAliases>
            
            <!-- 针对单个别名定义
            type:类型的路径
            alias:别名
             -->
            <typeAlias type="cn.itcast.mybatis.po.User" alias="user"/> 
            <!-- 批量别名定义 
            指定包名,mybatis自动扫描包中的po类,自动定义别名,别名就是类名(首字母大写或小写都可以)
            -->
            <package name="cn.itcast.mybatis.po"/>
            
        </typeAliases>
    

    4-4 mappers(映射配置)

    1 通过resource加载单个映射文件

    2 通过mapper接口加载单个mapper

    3 批量加载mapper(推荐使用)

    <mappers>
            <!-- <mapper resource="sqlmap/User.xml"/> -->
            
            <!--通过resource方法一次加载一个映射文件 -->
            <!-- <mapper resource="mapper/UserMapper.xml"/> -->
            
            <!-- 通过mapper接口加载单个 映射文件
            遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录 中
            上边规范的前提是:使用的是mapper代理方法
             -->
            <!-- <mapper class="cn.itcast.mybatis.mapper.UserMapper"/> -->
            
            <!-- 批量加载mapper
            指定mapper接口的包名,mybatis自动扫描包下边所有mapper接口进行加载
            遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录 中
            上边规范的前提是:使用的是mapper代理方法
             -->
            <package name="cn.itcast.mybatis.mapper"/>
        </mappers>
    

    5 输入映射(parameterType)和输出映射(resultType)

    输入映射:

    通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型。

    注意:
    1、使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
    2、如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象。
    3、只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象,不一致的属性的值为null。

    输出映射:

    使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
    如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象。
    只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象,不一致的属性的值为null。

        <!-- 用户信息综合查询
        #{userCustom.sex}:取出pojo包装对象中性别值
        ${userCustom.username}:取出pojo包装对象中用户名称
         -->
        <select id="findUserList" parameterType="cn.itcast.mybatis.po.UserQueryVo" 
                resultType="cn.itcast.mybatis.po.UserCustom">
                SELECT * FROM USER
        </select>
    
        @Test
        public void testFindUserList() throws Exception {
            
            SqlSession sqlSession = sqlSessionFactory.openSession();
            
            //创建UserMapper对象,mybatis自动生成mapper代理对象
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            
            //创建包装对象,设置查询条件
            UserQueryVo userQueryVo = new UserQueryVo();
            UserCustom userCustom = new UserCustom();
            //由于这里使用动态sql,如果不设置某个值,条件不会拼接在sql中
    //      userCustom.setSex("1");
            userCustom.setUsername("小明");
            //传入多个id
            List<Integer> ids = new ArrayList<Integer>();
            ids.add(1);
            ids.add(10);
            ids.add(16);
            //将ids通过userQueryVo传入statement中
            userQueryVo.setIds(ids);
            userQueryVo.setUserCustom(userCustom);
            //调用userMapper的方法
            
            List<UserCustom> list = userMapper.findUserList(userQueryVo);
            
            System.out.println(list);       
        }
    

    6 动态sql

    mybatis核心。对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。

    nobibi,show you my code

     @Test
        public void findUserCount() throws Exception  {
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            //创建UserMapper对象,mybatis自动生成mapper代理对象
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    
            //创建包装对象,设置查询条件
            UserQueryVo userQueryVo = new UserQueryVo();
            UserCustom userCustom = new UserCustom();
            userCustom.setSex("1");
            userCustom.setUsername("张三丰");
            userQueryVo.setUserCustom(userCustom);
    
            int count = userMapper.findUserCount(userQueryVo);
    
            System.out.println(count);
        }
    
    <!-- 定义sql片段
        id:sql片段的唯 一标识
        
        经验:是基于单表来定义sql片段,这样话这个sql片段可重用性才高
        在sql片段中不要包括 where
         -->
        <sql id="query_user_where">
            <if test="userCustom!=null">
              <if test="userCustom.sex!=null and userCustom.sex!=''">
                  and user.sex = #{userCustom.sex}
              </if>
                <if test="userCustom.username!=null and userCustom.username!=''">
                    and user.username LIKE '%${userCustom.username}%'
                </if>
            </if>
        </sql>
    
    <!-- 用户信息综合查询总数
        parameterType:指定输入类型和findUserList一样
        resultType:输出结果类型
         -->
        <select id="findUserCount" parameterType="cn.itcast.mybatis.po.UserQueryVo" resultType="int">
           SELECT count(*) FROM USER 
           
          <!-- 
        where可以自动去掉条件中的第一个and
         -->
        <where>
            <!-- 引用sql片段 的id,如果refid指定的id不在本mapper文件中,需要前边加namespace -->
            <include refid="query_user_where"></include>
            <!-- 在这里还要引用其它的sql片段  -->
        </where>       
        </select>
    

    感觉这个功能很NP,要善用。

    相关文章

      网友评论

          本文标题:Mybatis----(1)

          本文链接:https://www.haomeiwen.com/subject/eokeuftx.html