MyBatis入门

来源:互联网 发布:户外网络摄像机 编辑:程序博客网 时间:2024/04/28 00:48

MyBatis从入门到最后会讲解的内容:

基础知识(重点,内容量多)

对原生态jdbc程序(单独使用jdbc开发)问题总结mybatis框架原理 (掌握)mybatis入门程序    用户的增、删、改、查mybatis开发dao两种方法:    原始dao开发方法(程序需要编写dao接口和dao实现类)(掌握)    mybaits的mapper接口(相当于dao接口)代理开发方法(掌握)mybatis配置文件SqlMapConfig.xmlmybatis核心:    mybatis输入映射(掌握)    mybatis输出映射(掌握)mybatis的动态sql(掌握)

高级知识

订单商品数据模型分析高级结果集映射(一对一、一对多、多对多)mybatis延迟加载mybatis查询缓存(一级缓存、二级缓存)mybaits和spring进行整合(掌握)mybatis逆向工程

创建MySQL数据

导入下边脚本

下载地址

sql_table.sql:记录表结构。
sql_data.sql:可以理解为记录测试数据。在实际企业开发中,相当于提供了一个初始化数据脚本。

下面来回顾一下JDBC里面的原始代码:

    @Test    public void showUser(){        //数据库连接        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();                }            }        }    }

JDBC编程步骤:

1、 加载数据库驱动
2、 创建并获取数据库链接
3、 创建jdbc statement对象
4、 设置sql语句
5、 设置sql语句中的参数(使用preparedStatement)
6、 通过statement执行sql并获取结果
7、 对sql执行结果进行解析处理
8、 释放资源(resultSet、preparedstatement、connection)

JDBC问题总结:

1.数据库连接,使用时创建,不适用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响 数据库性能。

设想:使用数据库连接池管理数据库连接。

2.将sql语句硬编码到java代码中,如果sql语句修改,需要重新编译java代码,不利系统维护。

设想:将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译。

3.向PreparedStatement中设置参数,对占位符位置和设置参数值,硬编码在java代码中,不利于系统维护。

设想:将sql语句及占位符号和参数全部配置在xml中。

4.从resultSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护。

设想:将查询的结果集,自动映射成java对象。

Mybatis框架

Mybatis是什么??
  • MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis,实质上Mybatis对ibatis进行一些改进。
  • MyBatis 以前是在apache官网下载,之后被托管到googlecode下,再后来托管到GitHub下(https://github.com/mybatis/mybatis-3/releases)。
  • MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
  • Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
  • 其中比较重要的一点就是:1.MyBatis 让程序员主要精力放在sql上,通过MyBatis提供的映射方式,自由灵活生成(半自动化,大部分需要程序员编写sql) 满足需要的sql语句。2.MyBatis 可以将向 PreparedStatement 中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射)

MyBatis框架思路:

这里写图片描述

现在我们有个需求:

本篇博客就将按照下面内容作为驱动案例讲解:

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

开发环境配置:

第一步:

导入jar包。

下载jar包

其中你会看到的目录结构:

这里写图片描述

在lib目录下的jar包:

这里写图片描述

把核心包和依赖包都导入。

还有别忘了导入MySQL驱动包。

下载地址

第二步:

  • log4j.properties

在classpath下创建log4j.properties,内容如下:

classpath就是src下边

# Global logging configurationlog4j.rootLogger=DEBUG, stdout# Console output...log4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

这里写图片描述

第三步:

配置SqlMapConfig.xml

在src下创建SqlMapConfig.xml,如下:

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration>    <!-- 和spring整合后 environments配置将废除-->    <!--         下面的两个标签environments和environment对应的属性default和id能够填入的值:        work:工作模式        development:开发模式        注意:两个属性值不能够乱写    -->    <environments default="development">        <!--            这里可以配置多个环境:                为什么可以配置多个环境?                因为在大型项目的时候可能会出现跨数据库存值取值的情况。                比如:我在北京数据库里面取出值,然后在上海数据库里面删除值。这有可能发生的。这种类型叫做JTA,即Java Transaction API。        -->        <environment id="development">        <!-- 使用jdbc事务管理,事务控制由MyBatis-->            <transactionManager type="JDBC" />        <!-- 配置数据源,其中数据源的实现是使用数据库连接池提供,由MyBatis管理-->            <dataSource type="POOLED">            <!--                 数据源:                    POOLED:表示使用连接池,自带的。                    UNPOOLED:不使用连接池,每次使用连接后就断开。                    MANAGED:使用容器管理。笔者也不知道这是什么。。             -->                <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="" />            </dataSource>        </environment>    </environments></configuration>

第四步:

我们这里是查询User表内容,所以我们这里创建用户类:

public class User {    private Integer id;    private String username;    private Date birthday;    private Integer sex;    private String address;    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 Date getBirthday() {        return birthday;    }    public void setBirthday(Date birthday) {        this.birthday = birthday;    }    public Integer getSex() {        return sex;    }    public void setSex(Integer sex) {        this.sex = sex;    }    public String getAddress() {        return address;    }    public void setAddress(String address) {        this.address = address;    }    @Override    public String toString() {        return "User [id=" + id + ", username=" + username + ", birthday=" + birthday + ", sex=" + sex + ", address="                + address + "]";    }}

第五步:

编写用户类的映射文件。

映射文件命名:
User.xml(原始ibatis命名),mapper代理开发映射文件名称叫XXXMapper.xml,比如:UserMapper.xml、ItemsMapper.xml

我这里User类的映射文件名称为User.xml
在映射文件中配置sql语句。

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//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    将sql语句封装到mappedStatement对象中,所以将id称为statement的id    parameterType:指定输入 参数的类型,这里指定int型     #{}表示一个占位符号    #{id}:其中的id表示接收输入 的参数,参数名称就是id,如果输入 参数是简单类型,#{}中的参数名可以任意,可以value或其它名称    resultType:指定sql输出结果 的所映射的java对象类型,select指定resultType表示将单条记录映射成的java对象。     -->    <select id="findUserByid" parameterType="int" resultType="cn.domarvel.entity.User">        select * from user where id=#{id}    </select></mapper>

第六步:

在MyBatis核心配置文件中加载映射文件

    <!-- 加载映射文件 -->    <mappers>        <mapper resource="cn/domarvel/entity/User.xml"></mapper>    </mappers>

整体MyBatis的核心配置文件内容:

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration>    <!-- 和spring整合后 environments配置将废除-->    <!--         下面的两个标签environments和environment对应的属性default和id能够填入的值:        work:工作模式        development:开发模式        注意:两个属性值不能够乱写    -->    <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="" />            </dataSource>        </environment>    </environments>    <!-- 加载映射文件 -->    <mappers>        <mapper resource="cn/domarvel/entity/User.xml"></mapper>    </mappers></configuration>

第七步:

编写测试代码

    @Test    public void findUserById() {        SqlSession sqlSession=null;        try {            //以流的方式获取MyBatis的配置文件            InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");            //创建会话工厂,传入MyBatis的配置文件信息            SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);            //通过工厂得到SqlSession            sqlSession=sqlSessionFactory.openSession();            // 通过SqlSession操作数据库            // 第一个参数:映射文件中statement的id,等于=namespace.statement的id            // 第二个参数:指定和映射文件中所匹配的parameterType类型的参数            // sqlSession.selectOne结果 是与映射文件中所匹配的resultType类型的对象            // selectOne查询出一条记录            User user=sqlSession.selectOne("test.findUserByid", 1);            System.out.println(user);        } catch (IOException e) {            e.printStackTrace();        }finally {            // 释放资源            sqlSession.close();        }    }

可以不通过命名空间.id加载sql语句

通过命名空间.id访问配置文件的sql语句不是绝对的,可以不通过命名空间.id访问,如果id是唯一的,那么命名空间可以省略。
例如:

    <select id="findUserByid" parameterType="int" resultType="cn.domarvel.entity.User">        select * from user where id=#{id}    </select>//如果findUserByid是唯一的//那么可以在调用的时候把命名空间省略掉

这是笔者当前的工作目录:

这里写图片描述

根据用户名称模糊查询用户信息:

在User.xml中进行配置以下内容:

    <!-- 根据用户名称模糊查询用户信息,可能返回多条    resultType:指定就是单条记录所映射的java对象 类型    ${}:表示拼接sql串,将接收到参数的内容不加任何修饰拼接在sql中。    使用${}拼接sql,引起 sql注入    ${value}:接收输入 参数的内容,如果传入类型是简单类型,${}中只能使用value     -->    <select id="findUserByLikeName" parameterType="java.lang.String" resultType="cn.domarvel.entity.User">        select * from user where username like '%${value}%'    </select>

测试代码:

    @Test    public void findUserByLikeName(){        SqlSession sqlSession=null;        try {            //以流的方式获取MyBatis的配置文件            InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");            //创建会话工厂,传入MyBatis的配置文件信息            SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);            //通过工厂得到SqlSession            sqlSession=sqlSessionFactory.openSession();            // 通过SqlSession操作数据库            // 第一个参数:映射文件中statement的id,等于=namespace.statement的id            // 第二个参数:指定和映射文件中所匹配的parameterType类型的参数            // sqlSession.selectOne结果 是与映射文件中所匹配的resultType类型的对象            // selectOne查询出一条记录            List<User> list =sqlSession.selectList("test.findUserByLikeName", "小明");            for(User i:list){                System.out.println(i);            }            // 释放资源        } catch (IOException e) {            e.printStackTrace();        }finally {            sqlSession.close();        }    }

这个是当前测试代码,MyBatis发出的sql底层代码。很明显通过${value} 这个关键字符串起的作用是把字符串和字符串拼接起来,并且没有用到占位符。所以很容易引起sql注入攻击。所以不建议使用${}

DEBUG [main] - ==>  Preparing: select * from user where username like '%小明%' 

下面来讲个区别(重点):

需求:我们想要在数据表里面找到“陈小明”这个User并且输出。

有两种实现:

    @Override    public User findUserByNameMap(String name) throws Exception {        SqlSession sqlSession=sqlSessionFactory.openSession();        Map<String, User> resultsMap=sqlSession.selectMap("test.findUsers", "username");//第一个是声明操作id,第二个是指定表中的哪儿一个列名为键。        //查询结果为map,指定列名为键,查询结果为值的map        return resultsMap.get(name);    }    @Override    public User findUserByNameList(String name) throws Exception {        SqlSession sqlSession=sqlSessionFactory.openSession();        List<User> users=sqlSession.selectList("test.findUsers");        for(User i:users){            if(i.getUsername().equals(name)){                return i;            }        }        return null;    }

测试代码:

    @Test    public void findUserByNameMap() throws Exception{        System.out.println(userDao.findUserByNameMap("陈小明"));    }    @Test    public void findUserByNameList() throws Exception{        System.out.println(userDao.findUserByNameList("陈小明"));    }

看了上面的代码实现,我就想问,哪儿一个效率比较高??

其实我一直都没有怎么注意这些,但是我被问起来的时候,就发现了它的重要性。

很明显,根据Map查询的时候效率高!!因为我是直接根据Map索引取值的。而List是还要遍历判断是否为需要的值,这是很浪费时间的。

Map的数据结构是散列表,也就是Hash表。

给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。

而Hash表一般就是下面这个结构,数组+链表。其中数组会自动扩容。

这里写图片描述

添加用户:

编写User.xml用户映射文件:

    <!-- 添加用户     pojo是自定义类型的意思。    parameterType:指定输入 参数类型是pojo(包括 用户信息)    #{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL获取对象的属性值    -->    <insert id="insertSingleUser" parameterType="cn.domarvel.entity.User">        insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})    </insert>

测试代码:

    @Test    public void insertIntoUser(){        SqlSession sqlSession=null;        try {            //以流的方式获取MyBatis的配置文件            InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");            //创建会话工厂,传入MyBatis的配置文件信息            SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);            //通过工厂得到SqlSession            sqlSession=sqlSessionFactory.openSession();            // 通过SqlSession操作数据库            // 第一个参数:映射文件中statement的id,等于=namespace.statement的id            // 第二个参数:指定和映射文件中所匹配的parameterType类型的参数            // sqlSession.selectOne结果 是与映射文件中所匹配的resultType类型的对象            // selectOne查询出一条记录            sqlSession.insert("test.insertSingleUser", new User("FireLang", new Date(), 1, "LangIsland"));            //查询值的时候事务将会自动提交。添加值的时候事务是不会自动提交的,如果我们要提交事务需要自己手动提交。不提交事务,数据插入将不会成功。            sqlSession.commit();            // 释放资源        } catch (IOException e) {            e.printStackTrace();        }finally {            sqlSession.close();        }    }

DEBUG信息:

DEBUG [main] - ==>  Preparing: insert into user(username,birthday,sex,address) values(?,?,?,?) DEBUG [main] - ==> Parameters: FireLang(String), 2017-04-04 15:20:10.507(Timestamp), 1(Integer), LangIsland(String)

自增主键返回:

mysql自增主键,执行insert提交之前自动生成一个自增主键。
通过mysql函数获取到刚插入记录的自增主键:
LAST_INSERT_ID()

是insert之后调用此函数。

我们要实现把自增主键查询后放入到User对象里面。

User.xml配置文件配置:

    <!-- 添加用户     pojo是自定义类型的意思。    parameterType:指定输入 参数类型是pojo(包括 用户信息)    #{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL获取对象的属性值    -->    <insert id="insertSingleUser" parameterType="cn.domarvel.entity.User">        <!--         将插入数据的主键返回,返回到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>        insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})    </insert>

测试代码:

    @Test    public void insertIntoUser(){        SqlSession sqlSession=null;        try {            //以流的方式获取MyBatis的配置文件            InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");            //创建会话工厂,传入MyBatis的配置文件信息            SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);            //通过工厂得到SqlSession            sqlSession=sqlSessionFactory.openSession();            // 通过SqlSession操作数据库            // 第一个参数:映射文件中statement的id,等于=namespace.statement的id            // 第二个参数:指定和映射文件中所匹配的parameterType类型的参数            // sqlSession.selectOne结果 是与映射文件中所匹配的resultType类型的对象            // selectOne查询出一条记录            User user=new User("FireLangX", new Date(), 1, "LangIsland");            sqlSession.insert("test.insertSingleUser", user);            System.out.println("############ID= "+user.getId());            sqlSession.commit();            // 释放资源        } catch (IOException e) {            e.printStackTrace();        }finally {            sqlSession.close();        }    }

DEBUG输出的部分信息:

DEBUG [main] - ==>  Preparing: insert into user(username,birthday,sex,address) values(?,?,?,?) DEBUG [main] - ==> Parameters: FireLangX(String), 2017-04-04 15:56:13.383(Timestamp), 1(Integer), LangIsland(String)DEBUG [main] - <==    Updates: 1DEBUG [main] - ==>  Preparing: select LAST_INSERT_ID() DEBUG [main] - ==> Parameters: DEBUG [main] - <==      Total: 1############ID= 32

非自增主键返回(使用uuid()):

使用mysql的uuid()函数生成主键,需要修改表中id字段类型为string,长度设置成35位。

执行思路:
先通过uuid()查询到主键,将主键设置到 parameterType 指定的对象中

执行uuid()语句顺序相对于insert语句之前执行。

<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">            SELECT uuid()</selectKey>        insert into user(id,username,birthday,sex,address) value(#{id},#{username},#{birthday},#{sex},#{address})         <!-- 注意上面的sql语句要写插入的id -->


删除用户:

User.xml配置文件:

    <!--         删除用户:            根据id删除用户,需要输入id值    -->    <delete id="deleteUser" parameterType="java.lang.Integer">        delete from user where id=#{idx}    </delete>

测试代码:

    @Test    public void deleteUser(){        SqlSession sqlSession=null;        try {            //以流的方式获取MyBatis的配置文件            InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");            //创建会话工厂,传入MyBatis的配置文件信息            SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);            //通过工厂得到SqlSession            sqlSession=sqlSessionFactory.openSession();            // 通过SqlSession操作数据库            // 第一个参数:映射文件中statement的id,等于=namespace.statement的id            // 第二个参数:指定和映射文件中所匹配的parameterType类型的参数            // sqlSession.selectOne结果 是与映射文件中所匹配的resultType类型的对象            // selectOne查询出一条记录            sqlSession.delete("test.deleteUser", 33);            //必须手动提交事务            sqlSession.commit();            // 释放资源        } catch (IOException e) {            e.printStackTrace();        }finally {            sqlSession.close();        }    }


更新用户:

    <!-- 根据id更新用户    分析:    需要传入用户的id    需要传入用户的更新信息    parameterType指定user对象,包括 id和更新信息,注意:id必须存在    #{id}:从输入 user对象中获取id属性值     -->     <update id="updateUser" parameterType="cn.domarvel.entity.User">        update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}     </update>

测试代码:

    @Test    public void updateUser(){        SqlSession sqlSession=null;        try {            //以流的方式获取MyBatis的配置文件            InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");            //创建会话工厂,传入MyBatis的配置文件信息            SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);            //通过工厂得到SqlSession            sqlSession=sqlSessionFactory.openSession();            // 通过SqlSession操作数据库            // 第一个参数:映射文件中statement的id,等于=namespace.statement的id            // 第二个参数:指定和映射文件中所匹配的parameterType类型的参数            // sqlSession.selectOne结果 是与映射文件中所匹配的resultType类型的对象            // selectOne查询出一条记录            User user=new User("北斗", new Date(), 1, "FIREIsland");            user.setId(32);            sqlSession.update("test.updateUser", user);            //必须手动提交事务            sqlSession.commit();            // 释放资源        } catch (IOException e) {            e.printStackTrace();        }finally {            sqlSession.close();        }    }

整体User.xml配置:

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//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    将sql语句封装到mappedStatement对象中,所以将id称为statement的id    parameterType:指定输入 参数的类型,这里指定int型     #{}表示一个占位符号    #{id}:其中的id表示接收输入 的参数,参数名称就是id,如果输入 参数是简单类型,#{}中的参数名可以任意,可以value或其它名称    resultType:指定sql输出结果 的所映射的java对象类型,select指定resultType表示将单条记录映射成的java对象。     -->    <select id="findUserByid" parameterType="int" resultType="cn.domarvel.entity.User">        select * from user where id=#{id}    </select>    <!-- 根据用户名称模糊查询用户信息,可能返回多条    resultType:指定就是单条记录所映射的java对象 类型    ${}:表示拼接sql串,将接收到参数的内容不加任何修饰拼接在sql中。    使用${}拼接sql,引起 sql注入    ${value}:接收输入 参数的内容,如果传入类型是简单类型,${}中只能使用value     -->    <select id="findUserByLikeName" parameterType="java.lang.String" resultType="cn.domarvel.entity.User">        select * from user where username like '%${value}%'    </select>    <!-- 添加用户     pojo是自定义类型的意思。    parameterType:指定输入 参数类型是pojo(包括 用户信息)    #{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL获取对象的属性值    -->    <insert id="insertSingleUser" parameterType="cn.domarvel.entity.User">        <!--         将插入数据的主键返回,返回到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>        insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})    </insert>    <!--         删除用户:            根据id删除用户,需要输入id值    -->    <delete id="deleteUser" parameterType="java.lang.Integer">        delete from user where id=#{idx}    </delete>    <!-- 根据id更新用户    分析:    需要传入用户的id    需要传入用户的更新信息    parameterType指定user对象,包括 id和更新信息,注意:id必须存在    #{id}:从输入 user对象中获取id属性值     -->     <update id="updateUser" parameterType="cn.domarvel.entity.User">        update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}     </update></mapper>

总结

parameterType

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

resultType

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

#{}和${}

#{}表示一个占位符号,#{}接收输入参数,类型可以是简单类型,pojo、hashmap。为什么用#{}代表,而不用"?"代表占位符呢??因为框架将sql和程序代码分离开,所以无法直接确认参数的含义,到底"?"代表哪儿个参数等等,所以框架采用了特殊的符号来代替"?"号。如果接收简单类型,#{}中可以写成value或其它名称。#{}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。
${}表示一个拼接符号,会引用sql注入,所以不建议使用${}。${}接收输入参数,类型可以是简单类型,pojo、hashmap。如果接收简单类型,${}中只能写成value。${}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。

这里要注意一点:如果我们传递过来的参数只是一个简单类型(例如String,Interger等,并没有封装多个属性的叫做简单类型,而封装多个属性并且提供了setter和getter的叫做封装类型。Map是封装类型,取值可以根据key取值。),并且有多个#{}(名称可以任意取,如#{aa}、#{bb}),那么这里的所有#{}占位符的最终获取值都相同。

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

能看到的文章最后就是非常有耐心的人,或者是直接跳过的人。笔者这里给你们一个奖励,MyBatis中文API文档在线阅读

本博客MyBatis入门代码下载

2 0
原创粉丝点击