zoukankan      html  css  js  c++  java
  • MyBatis入门基础(一)

    一:对原生态JDBC问题的总结

      新项目要使用mybatis作为持久层框架,由于本人之前一直使用的Hibernate,对mybatis的用法实在欠缺,最近几天计划把mybatis学习一哈,特将学习笔记记录于此,方便大家参考,也方便自己查阅。

      话不多说,先看看原始的JDBC程序代码,看看这样的代码存在什么问题。

    复制代码
    package com.utils;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    /**
     * @ClassName: JdbcTest
     * @Description: TODO(原始的JDBC操作数据库)
     * @author warcaft
     * @date 2015-6-27 下午3:31:22
     * 
     */
    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", "root");
                // 定义sql语句 ?表示占位符
                String sql = "select * from t_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对象。

    二:MyBatis框架

      1.MyBatis是什么?(下载地址:https://github.com/mybatis/mybatis-3/releases) 

       MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis,实质上Mybatis对ibatis进行一些改进。 

      MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

      Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

      2.MyBatis架构图

      

    1、mybatis配置

    SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。

    mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。

     2、通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂

     3、由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。

     4、mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。

     5、Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。

     6、Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。

     7、Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

    三:mybatis入门程序

    1.需求:(1).根据用户id(主键)查询用户信息 (2).根据用户名称模糊查询用户信息(3).添加用户 4).删除用户(5).更新用户

    2.环境:java环境:JDK1.7,eclipse,Mysql5.1

    3.工程目录结构

     

    4.从mybatis的jar包结构可知mybatis用的是log4j记录日志,所以log4j.properties文件内容如下:

    复制代码
    # Global logging configuration
    #在开发的环境下,日志级别要设置成DEBUG,生产环境设置成info或error
    log4j.rootLogger=DEBUG, stdout
    # Console output...
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
    复制代码

    5.SqlMapConfig.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>
        <!-- 和spring整合后 environments配置将废除-->
        <environments default="development">
            <environment id="development">
            <!-- 使用jdbc事务管理,事务控制由mybatis管理-->
                <transactionManager type="JDBC" />
            <!-- 数据库连接池,由mybatis管理-->
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver" />
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
                    <property name="username" value="root" />
                    <property name="password" value="root" />
                </dataSource>
            </environment>
        </environments>
    <!-- 加载映射文件 -->
        <mappers>
            <mapper resource="sqlmap/User.xml"/>
        </mappers>
    </configuration>
    复制代码

    6.实体User.java内容

    复制代码
    package com.mybatis.entity;
    
    import java.util.Date;
    
    /**
     * @ClassName: User
     * @Description: TODO(用户实体)
     * @author warcaft
     * @date 2015-6-27 下午1:56:02
     * 
     */
    public class User {
        // 属性名称和数据库字段名称保持一致
        private Integer id;
        // 姓名
        private String username;
        // 性别
        private String sex;
        // 地址
        private String address;
        // 生日
        private Date birthday;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        @Override
        public String toString() {
            return "User [id=" + id + ", username=" + username + ", sex=" + sex
                    + ", address=" + address + ", birthday=" + birthday + "]";
        }
    
    }
    复制代码

    7.映射文件User.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进行分类化的管理,理解为sql隔离
        注意:使用mapper代理开发时,namespace有特殊作用
     -->
    <mapper namespace="test">
    <!-- 在映射文件中配置很多sql语句 -->
    <!-- 需求:通过Id查询用户表的记录 -->
    <!-- 通过SELECT执行数据库查询 
        id:标识映射文件中的sql,称为statement的id;
            将sql语句封装在mapperStatement的对象中,所以Id称为Statement的id;
        parameterType:指定输入参数的类型,这里指定int型
        #{}:表示一个占位符;
        #{id}:其中Id表示接收输入的参数,参数名称就是Id,如果输入参数是简单类型,#{}中的参数名可以任意,可以是value或者其它名称;
        resultType:指定sql输出结果所映射的java对象类型,select指定resultType表示将单条记录映射成java对象。
    -->
    <select id="findUserById" parameterType="int" resultType="com.mybatis.entity.User" >
        select * from t_user where id=#{id}
    </select>
    <!-- 根据用户名称模糊查询用户信息,可能返回多条数据
        resultType:指定的就是单条记录所映射的java类型;
        ${}:表示拼接sql字符串,将接收到的参数内容不加任何修饰拼接在sql中.
        使用${}拼接sql,可能会引起sql注入
        ${value}:接收输入参数的内容,如果传入的是简单类型,${}中只能使用value
     -->
    <select id="findUserByName" parameterType="java.lang.String" resultType="com.mybatis.entity.User" >
        select * from t_user where username LIKE '%${value}%'
    </select>
    <!-- 添加用户 
    parameterType:指定输入的参数类型是pojo(包括用户信息);
    #{}中指定pojo的属性名称,接收到pojo对象的属性值    ,mybatis通过OGNL(类似struts2的OGNL)获取对象的属性值
    -->
    <insert id="insertUser" parameterType="com.mybatis.entity.User" >
        <!-- 
            将insert插入的数据的主键返回到User对象中;
            select last_insert_id():得到刚insert进去记录的主键值,只适用于自增主键;
            keyProperty:将查询到的主键值,设置到parameterType指定的对象的那个属性
            order:select last_insert_id()执行顺序,相对于insert语句来说它的执行顺序。
            resultType:指定select last_insert_id()的结果类型;
         -->
        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
            select last_insert_id()
        </selectKey>
        <!-- 
            使用mysql的uuid(),实现非自增主键的返回。
            执行过程:通过uuid()得到主键,将主键设置到user对象的Id的属性中,其次,在insert执行时,从user对象中取出Id属性值;
         <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
            select uuid()
        </selectKey>
            insert into t_user (id,username,birthday,sex,address) values(#{id},#{username},#{birthday},#{sex},#{address})
         -->
        insert into t_user (username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
    </insert>
    <!-- 删除用户 
        根据ID删除用户,需要输入Id值
    -->
        <delete id="deleteUser" parameterType="java.lang.Integer">
            delete from t_user where id=#{id}
        </delete>
    <!-- 更新用户 
        需要传入用户的Id和用户的更新信息
        parameterType:指定User对象,包括Id和用户的更新信息,注意:Id是必须存在的
        #{id}:从输入的User对象中获取Id的属性值
    -->
    <update id="updateUser" parameterType="com.mybatis.entity.User">
        update t_user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} 
        where id=#{id}
    </update>
    
    </mapper>
    复制代码

    8.测试程序MybatisService.java代码

    复制代码
    package com.mybatis.service;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Date;
    import java.util.List;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.Test;
    
    import com.mybatis.entity.User;
    
    /**
     * @ClassName: MybatisService
     * @Description: TODO(mybatis入门程序)
     * @author warcaft
     * @date 2015-6-27 下午4:49:49
     * 
     */
    public class MybatisService {
        // 根据Id查询用户信息,得到一条记录结果
        @Test
        public void findUserByIdTest() {
            // mybatis的配置文件
            String resource = "SqlMapConfig.xml";
            InputStream inputStream = null;
            SqlSession sqlSession = null;
            try {
                inputStream = Resources.getResourceAsStream(resource);
                // 1.创建会话工场,传入mybatis的配置文件信息
                SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                        .build(inputStream);
    
                // 2.通过工厂得到SqlSession
                sqlSession = sqlSessionFactory.openSession();
    
                // 3.通过sqlSession操作数据库
                // 第一个参数:映射文件中的statement的Id,等于namespace + "." + statement的id;
                // 第二个参数:指定和映射文件中所匹配的parameterType类型的参数;
                // sqlSession.selectOne结果是与映射文件所匹配的resultType类型的对象;
                // selectOne:查询一条结果
                User user = sqlSession.selectOne("test.findUserById", 1);
                System.out.println(user.toString());
    
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (sqlSession != null) {
                    sqlSession.close();
                }
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        // 根据姓名模糊查询用户信息,得到一条或多条记录结果
        @Test
        public void findUserByNameTest() {
            // mybatis的配置文件
            String resource = "SqlMapConfig.xml";
            InputStream inputStream = null;
            SqlSession sqlSession = null;
            try {
                inputStream = Resources.getResourceAsStream(resource);
                // 1.创建会话工场,传入mybatis的配置文件信息
                SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                        .build(inputStream);
    
                // 2.通过工厂得到SqlSession
                sqlSession = sqlSessionFactory.openSession();
    
                // 3.通过sqlSession操作数据库
                // 第一个参数:映射文件中的statement的Id,等于namespace + "." + statement的id;
                // 第二个参数:指定和映射文件中所匹配的parameterType类型的参数;
                // sqlSession.selectOne结果是与映射文件所匹配的resultType类型的对象;
                // list中的user和resultType类型一致
                List<User> list = sqlSession.selectList("test.findUserByName", "小");
                System.out.println(list);
    
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (sqlSession != null) {
                    sqlSession.close();
                }
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        // 添加用户
        @Test
        public void insertUserTest() {
            // mybatis的配置文件
            String resource = "SqlMapConfig.xml";
            InputStream inputStream = null;
            SqlSession sqlSession = null;
            try {
                inputStream = Resources.getResourceAsStream(resource);
                // 1.创建会话工场,传入mybatis的配置文件信息
                SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                        .build(inputStream);
                // 2.通过工厂得到SqlSession
                sqlSession = sqlSessionFactory.openSession();
                //插入用户的对象
                User user = new User();
                user.setUsername("小红");
                user.setBirthday(new Date());
                user.setSex("1");
                user.setAddress("上海");
                // 3.通过sqlSession操作数据库
                // 第一个参数:映射文件中的statement的Id,等于namespace + "." + statement的id;
                // 第二个参数:指定和映射文件中所匹配的parameterType类型的参数;
                // sqlSession.selectOne结果是与映射文件所匹配的resultType类型的对象;
                sqlSession.insert("test.insertUser", user);
                //执行提交事务
                sqlSession.commit();
                
                //项目中经常需要 获取新增的用户的主键
                System.out.println(user.getId());
    
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (sqlSession != null) {
                    sqlSession.close();
                }
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        
        // 根据Id删除用户
            @Test
            public void deleteUserTest() {
                // mybatis的配置文件
                String resource = "SqlMapConfig.xml";
                InputStream inputStream = null;
                SqlSession sqlSession = null;
                try {
                    inputStream = Resources.getResourceAsStream(resource);
                    // 1.创建会话工场,传入mybatis的配置文件信息
                    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                            .build(inputStream);
                    // 2.通过工厂得到SqlSession
                    sqlSession = sqlSessionFactory.openSession();
                    // 3.通过sqlSession操作数据库
                    // 第一个参数:映射文件中的statement的Id,等于namespace + "." + statement的id;
                    // 第二个参数:指定和映射文件中所匹配的parameterType类型的参数;
                    // sqlSession.selectOne结果是与映射文件所匹配的resultType类型的对象;
                    //传入Id,删除用户
                    sqlSession.delete("test.deleteUser", 7);
                    //执行提交事务
                    sqlSession.commit();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (sqlSession != null) {
                        sqlSession.close();
                    }
                    if (inputStream != null) {
                        try {
                            inputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            
            // 根据Id更新用户信息
            @Test
            public void updateUserTest() {
                // mybatis的配置文件
                String resource = "SqlMapConfig.xml";
                InputStream inputStream = null;
                SqlSession sqlSession = null;
                try {
                    inputStream = Resources.getResourceAsStream(resource);
                    // 1.创建会话工场,传入mybatis的配置文件信息
                    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                            .build(inputStream);
                    // 2.通过工厂得到SqlSession
                    sqlSession = sqlSessionFactory.openSession();
                    //更新用户的信息
                    User user = new User();
                    user.setId(2);
                    user.setUsername("小黑");
                    user.setBirthday(new Date());
                    user.setSex("2");
                    user.setAddress("上海");
                    // 3.通过sqlSession操作数据库
                    // 第一个参数:映射文件中的statement的Id,等于namespace + "." + statement的id;
                    // 第二个参数:指定和映射文件中所匹配的parameterType类型的参数;
                    // sqlSession.selectOne结果是与映射文件所匹配的resultType类型的对象;
                    //更具Id更新用户
                    sqlSession.update("test.updateUser", user);
                    //执行提交事务
                    sqlSession.commit();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (sqlSession != null) {
                        sqlSession.close();
                    }
                    if (inputStream != null) {
                        try {
                            inputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
    }
    复制代码

    9.数据库所用sql脚本

    复制代码
    CREATE TABLE t_user (
      id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
      username VARCHAR(30) NOT NULL COMMENT '用户名称',
      birthday DATE DEFAULT NULL COMMENT '生日',
      sex CHAR(2) DEFAULT NULL COMMENT '性别',
      address VARCHAR(256) DEFAULT NULL COMMENT '地址'
    );
    INSERT INTO t_user (username,birthday,sex,address)
                                    VALUES
                       ('小A','2015-06-27','2','北京'),
                       ('小B','2015-06-27','2','北京'),
                       ('小C','2015-06-27','1','北京'),
                       ('小D','2015-06-27','2','北京');
    复制代码

    四:mybatis和Hibernate的本质区别与应用场景

    hibernate:是一个标准ORM框架(对象关系映射),入门门槛较高的,不需要程序写sqlsql语句自动生成了,对sql语句进行优化、修改比较困难的。

    应用场景:

         适用与需求变化不多的中小型项目,比如:后台管理系统,erpormoa。。

    mybatis:专注是sql本身,需要程序员自己编写sql语句,sql修改、优化比较方便。mybatis是一个不完全 的ORM框架,虽然程序员自己写sqlmybatis 也可以实现映射(输入映射、输出映射)。

    应用场景:

         适用与需求变化较多的项目,比如:互联网项目。

    五:小结

    1.parameterType和resultType

      parameterType:在映射文件中通过parameterType指定输入 参数的类型。

      resultType:在映射文件中通过resultType指定输出结果的类型

     2.#{}和${}

    #{}表示一个占位符号,#{}接收输入参数,类型可以是简单类型,pojo、hashmap;

    如果接收简单类型,#{}中可以写成value或其它名称;

    #{}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。

    sql使{};

    ${}接收输入参数,类型可以是简单类型,pojo、hashmap;

    如果接收简单类型,${}中只能写成value;

    ${}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。

    3.selectOne()和selectList()

      selectOne表示查询出一条记录进行映射。如果使用selectOne可以实现使用selectList也可以实现(list中只有一个对象)。

      selectList表示查询出一个列表(多条记录)进行映射。如果使用selectList查询多条记录,不能使用selectOne

      如果使用selectOne报错: org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 4

  • 相关阅读:
    LeetCode Count of Range Sum
    LeetCode 158. Read N Characters Given Read4 II
    LeetCode 157. Read N Characters Given Read4
    LeetCode 317. Shortest Distance from All Buildings
    LeetCode Smallest Rectangle Enclosing Black Pixels
    LeetCode 315. Count of Smaller Numbers After Self
    LeetCode 332. Reconstruct Itinerary
    LeetCode 310. Minimum Height Trees
    LeetCode 163. Missing Ranges
    LeetCode Verify Preorder Serialization of a Binary Tree
  • 原文地址:https://www.cnblogs.com/lixuwu/p/5676128.html
Copyright © 2011-2022 走看看