Mybatis--day01

非本人总结的笔记,抄点笔记复习复习。感谢传智博客及黑马程序猿
成长

什么是Mybatis

​ MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。 MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
​ Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

单独使用jdbc开发存在的问题

实现步骤

  1. 加载数据库驱动。根据不同的数据库选择不同的驱动。
  2. 创建一个连接。获得一个Connection对象。
  3. 创建一个prepareStatement对象,封装了sql语句。
  4. 设置参数。
  5. 执行查询获得一个ResultSet对象。
  6. 遍历resultSet对象。

数据库

数据库

代码实现

存在的问题

  1. 数据库驱动存在硬编码的问题。写到配置文件中来解决。
  2. 数据库连接串、用户名、密码存在硬编码的问题。
  3. Sql语句硬编码
  4. 参数设置不灵活
  5. 查询结果最好是返回一个pojo对象或者是pojo列表。
  6. 每次查询都需要开启连接关闭连接。浪费性能。需要使用数据库连接池。

Mybatis框架架构

Mybatis框架架构

Mybatis的入门程序

Mybatis的下载

mybatis的代码由github.comg管理,地址:https://github.com/mybatis/mybatis-3/releases

目录结构

需求

实现以下功能:
根据用户id查询一个用户信息
根据用户名称模糊查询用户信息列表
添加用户
更新用户
删除用户

入门程序实现

工程搭建

第一步:创建一个java工程。
第二步:导入jar包。包括mybatis的jar包、mybatis依赖的jar包、mysql的数据库驱动。
第三步:创建一个log4j.properties。方便查看sql语句用的。
第四步:创建一个SqlMapConfig.xml。配置数据库连接池。
第五步:创建Mapper映射文件。
第六步:编码。

项目

SqlMapConfig.xml

在classpath下创建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事务管理 -->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池 -->
            <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>
    
    </mappers>
</configuration>

Mapper映射文件

习惯上mapper映射文件的名称和数据库的表名一致。Ibatis时代的习惯。

<?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语句隔离,后面还有其他用途。 -->
<mapper namespace="test">
</mapper>

在SqlMapConfig.xml中加载mapper映射文件

<!-- 加载Mapper映射文件 -->
<mappers>
    <!-- resource从classpath下开始查找 -->
    <mapper resource="sqlmap/user.xml"/>
</mappers>

根据用户id查询一个用户信息

创建一个POJO保存返回结果

POJO的属性要求和数据库中的字段相对应

public class User {

    private int id;
    private String username;// 用户姓名
    private String sex;// 性别
    private Date birthday;// 生日
    private String address;// 地址
    
    //set和get方法
}

Sql语句

select * from user where id = 10

Mapper文件

需要把sql语句写到user.xml这个mapper映射文件中

<?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语句隔离,后面还有其他用途。 -->
<mapper namespace="test">
    <!-- 
        select:如果是一个select语句就需要使用select节点。
        id就是一个sql语句的id,代表一个sql语句。起个名字叫做StatementId。
        parameterType:参数的类型
        resultType:返回结果的类型,可以是pojo类型,需要pojo的全限定名。
        #{}:是一个占位符。相当于jdbc中的“?”,括号内容的名称,如果是简单数据类型可以随便起。
     -->
    <select id="getUserById" parameterType="int" resultType="cn.itcast.pojo.User">
        SELECT * from user where id = #{id}
    </select>
</mapper>

查询方法

/**
* 根据id查询用户信息
*/
@Test
public void getUserById() throws Exception {
    //创建一SqlSessionFactory
    //把配置文件读取到流中
    InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
    //创建SqlSessionFactory对象
    SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //创建sqlsession对象
    SqlSession sqlSession = sessionFactory.openSession();
    //查询一条记录使用selectOne方法
    //第一个参数:statementID
    //第二个参数:sql语句用到的参数
    User user = sqlSession.selectOne("test.getUserById", 10);
    System.out.println(user);
    //关闭sqlsession
    sqlSession.close();
}

根据用户名查询用户

Sql语句

SELECT * from user where username LIKE '%张三%'

第一种方法

Mapper文件

<!-- 根据用户名查询用户 -->
<!-- resultType是返回结果中一条记录的类型 -->
<select id="getUserByName" parameterType="string" resultType="cn.itcast.pojo.User">
    SELECT * from user where username LIKE #{name}
</select>

测试方法

@Test
public void getUserByName() throws Exception {
    SqlSession sqlSession = sessionFactory.openSession();
    //返回结果是多条记录使用selectList
    List<User> userList = sqlSession.selectList("test.getUserByName", "%张三%");
    System.out.println(userList);
    sqlSession.close();
}

第二种方法

Mapper文件

<!-- 根据用户名查询用户 -->
<!-- resultType是返回结果中一条记录的类型 -->
<!-- ${}:字符串拼接指令。可以拼装成一个完整的sql语句。缺点不能防止sql注入
  ${}内部的名称,如果是简单数据类型,必须是value
  -->
<select id="getUserByName" parameterType="string" resultType="cn.itcast.pojo.User">
    <!-- SELECT * from user where username LIKE #{name} -->
    SELECT * from user where username LIKE '%${value}%'
</select>

测试方法

@Test
public void getUserByName() throws Exception {
    SqlSession sqlSession = sessionFactory.openSession();
    //返回结果是多条记录使用selectList
    //List<User> userList = sqlSession.selectList("test.getUserByName", "%张三%");
    List<User> userList = sqlSession.selectList("test.getUserByName", "张三");
    System.out.println(userList);
    sqlSession.close();
}

添加用户

Sql语句

INSERT INTO user`(username,birthday,sex,address) VALUES('','','','')

Mapper文件

<!-- 添加用户 -->
<!-- 取对象中的属性直接使用#{}来取,括号中的名称必须是对象的属性名 -->
<insert id="insertUser" parameterType="cn.itcast.pojo.User">
        INSERT INTO `user`(username,birthday,sex,address) 
        VALUES(#{username},#{birthday},#{sex},#{address})
</insert>

测试方法

@Test
public void insertUser() throws Exception {
        SqlSession sqlSession = sessionFactory.openSession();
        //添加用户
        User user = new User();
        user.setUsername("入云龙");
        user.setSex("1");
        user.setAddress("天津蓟县");
        user.setBirthday(new Date());
        sqlSession.insert("test.insertUser", user);
        sqlSession.commit();
        sqlSession.close();
}

主键返回

在mysql中可以使用SELECT LAST_INSERT_ID();方法取当前事务中最后生成的id。在mybatis可以使用主键返回方法,把主键取出来返回给java程序。

<!-- 添加用户 -->
    <!-- 取对象中的属性直接使用#{}来取,括号中的名称必须是对象的属性名 -->
    <insert id="insertUser" parameterType="cn.itcast.pojo.User">
        <!-- keyProperty:user对象的主键属性
            resultType:主键的数据类型
            order:取主键语句的执行时机。BEFORE:在插入之前执行     AFTER:插入之后执行
          -->
        <selectKey keyProperty="id" resultType="int" order="AFTER">
            <!-- mysql取主键的函数 -->
            SELECT LAST_INSERT_ID();
        </selectKey>
        INSERT INTO `user`(username,birthday,sex,address) 
        VALUES(#{username},#{birthday},#{sex},#{address})
    </insert>

修改用户

Sql语句

UPDATE USER SET username = ' ', birthday= ' ', sex= ' ', address = '' WHERE id= 10

Mapper文件

<!-- 修改用户信息 -->
<update id="updateUser" parameterType="cn.itcast.pojo.User">
    UPDATE USER
    SET username = #{username},
    birthday = #{birthday},
    sex = #{sex},
    address = #{address}
    WHERE
    id = #{id}
</update>

测试方法

@Test
    public void updateUser() throws Exception {
        SqlSession sqlSession = sessionFactory.openSession();
        //取用户信息
        User user = sqlSession.selectOne("test.getUserById", 28);
        user.setUsername("武松");
        user.setAddress("清河县");
        sqlSession.update("test.updateUser", user);
        //提交修改
        sqlSession.commit();
        sqlSession.close();
    }

删除用户

Sql语句

DELETE from user where id=10

Mapper文件

<!-- 删除用户 -->
<delete id="deleteUserById" parameterType="int">
    DELETE from user where id=#{id}
</delete>

测试方法

@Test
public void deleteUserById() {
    SqlSession sqlSession = sessionFactory.openSession();
    sqlSession.delete("test.deleteUserById", 28);
    sqlSession.commit();
    sqlSession.close();
}

Mybatis和Hibernate的区别

  1. Mybatis并不是一个完全的orm框架。Hibernate是面向对象,可以不使用sql语句。Mybatis是面向sql语句的。专注的是输入映射返回值映射以及sql语句的灵活性。
  2. Mybatis门槛比较低,学习起来比较简单。查询性能,hibernate需要对性能进行优化,需要一个高手。Mybatis只需要对sql优化即可。
  3. Hibernate主要是应用在传统项目,开发速度很快。Mybatis主要用于互联网领域。适用于变化比较快的领域。
  4. 选择框架时,根据团队的技术储备。选择比较熟悉的框架。

使用Mybatis开发dao的方法

Sqlsession应用范围

Sqlsession

本身是线程不安全的,最佳应用范围应该是方法级别。

SqlsessionFactory

工厂类,创建Sqlsession的。此对象应该是单例模式出现在系统中,一个系统中只有一个SqlsessionFactory对象。

SqlsessionFactoryBuilder

当做一个工具类使用,创建完SqlsessionFactory对象就不用了。

传统方式

接口+实现类的方式

Dao

public class UserDaoImpl implements UserDao {
    
    private SqlSessionFactory sessionFactory;
    
    //构造方法中注入SqlSessionFactory对象。
    public UserDaoImpl(SqlSessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Override
    public User getUserById(int id) {
        
        SqlSession sqlSession = sessionFactory.openSession();
        User user = sqlSession.selectOne("test.getUserById", id);
        sqlSession.close();
        return user;
    }

    @Override
    public List<User> getUserByName(String name) {
        SqlSession sqlSession = sessionFactory.openSession();
        List<User> userList = sqlSession.selectList("test.getUserByName", name);
        sqlSession.close();
        return userList;
    }

    @Override
    public void insertUser(User user) {
        SqlSession sqlSession = sessionFactory.openSession();
        sqlSession.insert("test.insertUser", user);
        sqlSession.commit();
        sqlSession.close();
    }

}

测试方法

public class UserDaoTest {
    
    private SqlSessionFactory sessionFactory;
    
    @Before
    public void init() throws Exception {
        // 创建一SqlSessionFactory
        // 把配置文件读取到流中
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 创建SqlSessionFactory对象
        sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void testGetUserById() {
        UserDao userDao = new UserDaoImpl(sessionFactory);
        User user = userDao.getUserById(10);
        System.out.println(user);
    }

    @Test
    public void testGetUserByName() {
        UserDao userDao = new UserDaoImpl(sessionFactory);
        List<User> list = userDao.getUserByName("张三");
        System.out.println(list);
    }

    @Test
    public void testInsertUser() {
        UserDao userDao = new UserDaoImpl(sessionFactory);
        User user = new User();
        user.setUsername("武大郎");
        user.setBirthday(new Date());
        user.setSex("1");
        user.setAddress("清河县");
        userDao.insertUser(user);
    }

}

存在的问题

  1. dao中操作数据库的代码重复。可以考虑使用模板替代。
  2. statementId存在硬编码的问题。

使用Mapper代理的方法开发dao

只写接口不写实现类

开发规范

1、mapper文件的命名规则推荐是“表名+Mapper.xml”。接口文件的名称和mapper映射文件的名称一致。
2、Mapper文件的namespace必须是接口的全限定名。
3、StatementID必须和接口中方法的名称一致。
4、接口的参数类型必须和parameterType一致。
5、接口的返回值类型必须和ResultType一致。

代码实现

Mapper文件:

<?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语句隔离.
 如果使用Mapper代理形式开发,namespace必须是接口的全限定名-->
<mapper namespace="cn.mapper.UserMapper">
    <!-- 
        select:如果是一个select语句就需要使用select节点。
        id就是一个sql语句的id,代表一个sql语句。起个名字叫做StatementId。
        parameterType:参数的类型
        resultType:返回结果的类型,可以是pojo类型,需要pojo的全限定名。
        #{}:是一个占位符。相当于jdbc中的“?”,括号内容的名称,如果是简单数据类型可以随便起。
     -->
    <select id="getUserById" parameterType="int" resultType="cn.itcast.pojo.User">
        SELECT * from user where id = #{id}
    </select>
</mapper>

接口:

import cn.xx.pojo.User;

public interface UserMapper{
    Uasr getUserById(int id);
}

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事务管理 -->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池 -->
            <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>
    <!-- 加载Mapper映射文件 -->
    <mappers>
        <!-- resource从classpath下开始查找 -->
        <mapper resource="sqlmap/user.xml" />
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>

测试方法

@Test
public void testGetUserById() {
    SqlSession sqlSession = sessionFactory.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User user = userMapper.getUserById(10);
    System.out.println(user);
    sqlSession.close();
}

@Test
public void testGetUserByName() {
    SqlSession sqlSession = sessionFactory.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<User> list = userMapper.getUserByName("张三");
    System.out.println(list);
    sqlSession.close();
}

Mapper代理形式是官方推荐的使用方法。也是企业开发中最常用的方法。

SqlMapConfig.xml

配置内容

SqlMapConfig.xml中配置的内容和顺序如下:

properties(属性)

settings(全局配置参数)

typeAliases(类型别名)

typeHandlers(类型处理器)

objectFactory(对象工厂)

plugins(插件)

environments(环境集合属性对象)

​ environment(环境子属性对象)

​ transactionManager(事务管理)

​ dataSource(数据源)

mappers(映射器)

注意:Mybatis的配置文件配置项是有顺序的,不能打乱。

Properties

<!-- 属性配置 -->
<!-- 可以使用resource加载外部配置文件 -->
<properties resource="db.properties">
    <property name="JDBC_DRIVER" value="com.mysql.jdbc.Driver"/>
    <property name="JDBV_URL" value="jdbc:mysql://localhost:3306/mybatis"/>
    <property name="JDBC_USER" value="root"/>
    <property name="JDBC_PASSWORD" value="root"/>
</properties>

如果同时使用的话,加载顺序是先加载内部的属性,然后再加载外部的属性。如果有重名的属性会覆盖。最终生效的是外部的属性文件。

Settings

Mybatis的全局属性配置

<settings>
    <setting name="cacheEnabled" value="false"/>
    <setting name="lazyLoadingEnabled" value="true"/>
</settings>

配置项参见

Setting(设置) Description(描述) Valid Values(验证值组) Default(默认值)
cacheEnabled 在全局范围内启用或禁用缓存配置任何映射器在此配置下。 true | false TRUE
lazyLoadingEnabled 在全局范围内启用或禁用延迟加载。禁用时,所有协会将热加载。 true | false TRUE
aggressiveLazyLoading 启用时,有延迟加载属性的对象将被完全加载后调用懒惰的任何属性。否则,每一个属性是按需加载。 true | false TRUE
multipleResultSetsEnabled 允许或不允许从一个单独的语句(需要兼容的驱动程序)要返回多个结果集。 true | false TRUE
useColumnLabel 使用列标签,而不是列名。在这方面,不同的驱动有不同的行为。参考驱动文档或测试两种方法来决定你的驱动程序的行为如何。 true | false TRUE
useGeneratedKeys 允许JDBC支持生成的密钥。兼容的驱动程序是必需的。此设置强制生成的键被使用,如果设置为true,一些驱动会不兼容性,但仍然可以工作。 true | false FALSE
autoMappingBehavior 指定MyBatis的应如何自动映射列到字段/属性。NONE自动映射。 PARTIAL只会自动映射结果没有嵌套结果映射定义里面。 FULL会自动映射的结果映射任何复杂的(包含嵌套或其他)。 NONE, PARTIAL, FULL PARTIAL
defaultExecutorType 配置默认执行人。SIMPLE执行人确实没有什么特别的。 REUSE执行器重用准备好的语句。 BATCH执行器重用语句和批处理更新。 SIMPLE REUSE BATCH SIMPLE
defaultStatementTimeout 设置驱动程序等待一个数据库响应的秒数。 Any positive integer Not Set (null)
safeRowBoundsEnabled 允许使用嵌套的语句RowBounds。 true | false FALSE
mapUnderscoreToCamelCase 从经典的数据库列名A_COLUMN启用自动映射到骆驼标识的经典的Java属性名aColumn。 true | false FALSE
localCacheScope MyBatis的使用本地缓存,以防止循环引用,并加快反复嵌套查询。默认情况下(SESSION)会话期间执行的所有查询缓存。如果localCacheScope=STATMENT本地会话将被用于语句的执行,只是没有将数据共享之间的两个不同的调用相同的SqlSession。 SESSION | STATEMENT SESSION
dbcTypeForNull 指定为空值时,没有特定的JDBC类型的参数的JDBC类型。有些驱动需要指定列的JDBC类型,但其他像NULL,VARCHAR或OTHER的工作与通用值。 JdbcType enumeration. Most common are: NULL, VARCHAR and OTHER OTHER
lazyLoadTriggerMethods 指定触发延迟加载的对象的方法。 A method name list separated by commas equals,clone,hashCode,toString
defaultScriptingLanguage 指定所使用的语言默认为动态SQL生成。 A type alias or fully qualified class name. org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver
callSettersOnNulls 指定如果setter方法或地图的put方法时,将调用检索到的值是null。它是有用的,当你依靠Map.keySet()或null初始化。注意原语(如整型,布尔等)不会被设置为null。 true | false FALSE
logPrefix 指定的前缀字串,MyBatis将会增加记录器的名称。 Any String Not set
logImpl 指定MyBatis的日志实现使用。如果此设置是不存在的记录的实施将自动查找。 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING Not set
proxyFactory 指定代理工具,MyBatis将会使用创建懒加载能力的对象。 CGLIB | JAVASSIST

typeAliases

别名配置

Mybatis中定义的别名

别名 映射的类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
map Map

自定义别名

<!-- 别名配置 -->
<typeAliases>
        <!-- type:类的全限定名
            alias:别名
            别名不区分大小写
         -->
        <!-- <typeAlias type="cn.itcast.pojo.User" alias="user"/> -->
        <!-- 可以使用package批量定义别名,name属性就是pojo类所在的包名的全限定名
            别名就是类名,不区分大小写。
         -->
    <package name="cn.itcast.pojo"/>
</typeAliases>

Mappers

加载Mapper映射文件

<!-- 加载Mapper映射文件 -->
    <mappers>
        <!-- resource从classpath下开始查找 -->
        <mapper resource="sqlmap/user.xml"/>
        <!-- <mapper resource="mapper/UserMapper.xml"/> -->
        <!-- url配置的是文件的全路径 -->
        <!-- <mapper url="file:///D:\传智播客\10.课堂笔记\0413\mybatis\day01\source\MybatisSecond0413\config\mapper\UserMapper.xml"/> -->
        <!-- class指定接口的全限定名,要求Mapper映射文件和接口在同一个目录下,且名称相同。 -->
        <!-- <mapper class="cn.itcast.mapper.UserMapper"/> -->
        <!-- mapper接口所在包的全限定名,mybatis会扫描包下的接口,加载和接口同名的mapper映射文件 -->
        <package name="cn.itcast.mapper"/>
    </mappers>

Mapper映射文件

输入参数映射

基础数据类型

Integer、String、float等

POJO类型参数

例如添加用户、修改用户时使用user对象作为参数

POJO的包装类型

POJO中有一个属性,类型是POJO。

使用场合:查询条件复杂的时候,可以使用POJO的包装类型

QueryVo

​ |-user

​ |-item

创建一个QueryVo

package cn.itcast.pojo;

public class QueryVo {

    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
    
}

使用QueryVo查询

需求:根据用户id查询用户信息

QueryVo

​ |-User

​ |-id

Sql语句:select * from user where id=1

Mapper文件:

<select id="getUserByQueryVo" parameterType="QueryVo" resultType="user">
        <!-- 取属性名称使用“.”的方式来取 -->
        select * from user where id=#{user.id}
</select>

接口定义:

public interface UserMapper{
    User getUserByQueryVo(User user);   
}

测试方法:

@Test
public void testGetUserByQueryVo() {
    SqlSession sqlSession = sessionFactory.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    //创建一个QueryVo对象
    QueryVo queryVo = new QueryVo();
    //创建一个user对象
    User user = new User();
    user.setId(10);
    queryVo.setUser(user);
        
    User userResult = userMapper.getUserByQueryVo(queryVo);
    System.out.println(userResult);
        
    sqlSession.close();
}

Map类型

使用map作为参数进行映射。Map是key-value形式。绑定的时候应该使用#{key}。

返回值映射

返回基础数据类型

返回值是一个int或者String

Sql语句

select count(*) from user

Mapper 文件

<!-- 查询用户数量 -->
<select id="getUserCount" resultType="int">
    select count(*) from user
</select>

方法定义

public interface UserMapper {
    int getUserCount();
}

测试方法

@Test
public void testGetUserCount() throws Exception {
    SqlSession sqlSession = sessionFactory.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    int count = userMapper.getUserCount();
    System.out.println(count);
    sqlSession.close();
}

要求sql语句的查询结果必须是一条记录,可以是多个列,多个列的情况下只取第一列的内容返回。

POJO类型的返回结果

根据用户id查询用户信息。返回一个user对象就是一个pojo。

POJO的List结果

根据用户名查询用户信息返回一个用户列表就是一个pojoList。

返回一个Map类型

Pojo要求返回的结果中列名和pojo的属性名要一致。

如果返回结果是map类型,那么key就是列名,value就是就是此列的值。

Pojo属性名和列名不一致

  1. 修改sql语句,使用别名保证结果集中的列名和pojo的属性名一致。
  2. 使用ResultMap

ResultMap入门

resultMap定义

<!-- resultMap的定义 -->
<!-- type:接收返回结果的数据类型,此处为user -->
<resultMap type="user" id="userResultMap">
    <!-- 
     id:为主键列
     column:结果集中的主键列的列名
     property:对应user对象中保存主键属性。
     -->
    <id column="id" property="id"/>
    <!-- 普通列 -->
    <result column="uname" property="username"/>
    <result column="bday" property="birthday"/>
    <result column="sex" property="sex"/>
    <result column="addr" property="address"/>
</resultMap>
<!-- resultMap属性指定一个resultMap的id -->
<select id="getUserResultMap" resultMap="userResultMap">
    select id, username uname, birthday bday, sex, address addr from user
</select>

接口定义

public interface UserMapper{
    List<User> getUserResultMap();
}

测试方法

@Test
public void testGetUserResultMap() throws Exception {
    SqlSession sqlSession = sessionFactory.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<User> list = userMapper.getUserResultMap();
    System.out.println(list);
    sqlSession.close();
}

动态sql

If

需求:根据参数的不同调整查询条件

Mapper文件

<select id="getUserList" parameterType="user" resultType="user">
    select * from user
    where 0=0
    <if test="id!=null and id != 0">
        and id = #{id}
    </if>
    <if test="username != null and username != '' ">
        and username like '%${username}%'
    </if>
</select>

接口定义

public interface UserMapper{
    List<User> getUserList(User user);
}

测试方法

@Test
public void testGetUserList() throws Exception {
    SqlSession sqlSession = sessionFactory.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    //创建user对象作为查询条件
    User user = new User();
    user.setId(1);
    user.setUsername("张三");
    List<User> userList = userMapper.getUserList(user);
    System.out.println(userList);
    sqlSession.close();
}

Where

可以根据条件动态的添加where关键字,并且可以去掉多余的and

<select id="geUserList" parameterType="user" resultType="user">
    select * from user
    <where>
        <if test="id != null and id != 0">
            and id = #{id}
        </if>
        <if test="username != null and username != ''">
            and username like '%${username}%'
        </if>
    </where>
</select>

Foreach

创建QueryVo对象

public class QueryVo {
    private User user;
    private int[] ids;
    //省略get和set方法
}

Mapper文件

<select id="getUserList" parameterType="QueryVo" resultType="user">
        select * from user
        <where>
            <if test="user!=null">
                <if test="user.id!=null and user.id != 0">
                    and id = #{user.id}
                </if>
                <if test="user.username != null and user.username != '' ">
                    and username like '%${user.username}%'
                </if>
            </if>
            <if test="ids!=null">
                <!-- 
                collection:QueryVo中的集合属性ids
                open:前缀
                close:后缀
                item:循环的变量名称
                separator:分隔符
                 -->
                <foreach collection="ids" open="and id in(" close=")" item="id" separator=",">
                    #{id}
                </foreach>
            </if>
        </where>
</select>

接口定义

public interface UserMapper{
    List<User> getUserList(QueryVo queryVo);
}

测试方法

@Test
public void testGetUserList() throws Exception {
    SqlSession sqlSession = sessionFactory.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    //创建user对象作为查询条件
    User user = new User();
    //user.setId(1);
    //user.setUsername("张三");
    QueryVo queryVo = new QueryVo();
    queryVo.setUser(user);
    int[] ids = {1,10,16,22,24};
    queryVo.setIds(ids);
    List<User> userList = userMapper.getUserList(queryVo);
    System.out.println(userList);
    sqlSession.close();
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,009评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,808评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,891评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,283评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,285评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,409评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,809评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,487评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,680评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,499评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,548评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,268评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,815评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,872评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,102评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,683评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,253评论 2 341

推荐阅读更多精彩内容