03_Mybatis

文章目录

  • 入门案例
    • JDBC
    • Mybatis
  • Mybatis
    • Mybatis介绍
    • Mybatis的环境搭建
    • 动态代理
      • 增删改查示例
      • 事务
    • Mybatis的配置
      • properties
      • settings
      • typeAliases
      • environments
      • mappers
    • 输入映射
      • 一个参数
      • 多个参数
      • 按位置传值
      • 对象传值
      • 使用Map进行传值
    • #{}和${}的区别
    • 输出映射
      • 一个参数
      • 多个参数
      • 单个对象
      • 多个对象
      • resultMap

入门案例

JDBC

public class UserDaoImpl implements UserDao{
    @Override
    public User selectByPrimaryKey(Integer id) throws Exception {
        // 1.获得连接,如果后面需要提交事务,则执行connection.commit
        Connection connection = JdbcUtil.getConnection();
        // 2.预编译,预编译过程中传入了SQL语句
        PreparedStatement preparedStatement = connection
        .prepareStatement("select id, username, password, age, birthday
        , create_date, mobile from cskaoyan_user where id = ?");
        // 3.提供占位符位置的值
        preparedStatement.setInt(1,id);
        // 4.执行查询获得结果集
        ResultSet resultSet = preparedStatement.executeQuery();
        // 5.创建一个接收结果集中的值的实例
        User user = new User();
        while (resultSet.next()) {
            // 6.获得结果集中的username列(column)中的值
            String username = resultSet.getString("username");
            //   获得结果集中的password列(column)中的值
            String password = resultSet.getString("password");
            int age = resultSet.getInt("age");
            Date birthday = resultSet.getDate("birthday");
            Date createDate = resultSet.getDate("create_date");
            String mobile = resultSet.getString("mobile");
            user.setId(id);
            // 7.通过set方法封装给user实例中的username这个成员变量(property)
            user.setUsername(username);
            //   通过set方法封装给user实例中的password这个成员变量(property)
            user.setPassword(password);
            user.setAge(age);
            user.setBirthday(birthday);
            user.setCreateDate(createDate);
            user.setMobile(mobile);
        }
        return user;
    }
}


//定义了UserDao接口,我们传入id,可以查询user的记录出来
public interface UserDao {
    User selectByPrimaryKey(Integer id) throws Exception;
}
// 假如我们定义了实现类,那么我们可以这样子来调用获得user记录
public class JdbcExecution {
    // 查询id为2的用户
    public static void main(String[] args) throws Exception{
        UserDao userDao = new UserDaoImpl();
        User user = userDao.selectByPrimaryKey(2);
        System.out.println("user = " + user);
    }
}

这个过程比较繁琐,并且存在着很多定制化的内容和耦合

  • SQL语句和代码直接耦合在一起
  • 设置参数过程比较繁琐,对应的关系只有占位符的序号,如果有多个占位符?的话,容易出错
  • 查询结果集的使用比较繁琐
    • 手动调用构造方法来获得实例
    • 要关注列名从结果集中取出数据
    • 要关注列的类型手动调用不同的方法,比如getIntgetStringgetDate
    • 取出的值需要使用set方法来封装

Mybatis

  • 导包
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.10</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
  • 配置一个Mybatis的主配置文件,用来获取SqlSessionFactory
<?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>
    <!--添加日志的配置-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <!--环境配置,其实就是去配置数据库的连接-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url"
                          value="jdbc:mysql://localhost:3306/test_20240301?characterEncoding=utf8&amp;useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--读取映射文件-->
        <mapper resource="com/coo1heisenberg/dao/UserMapper.xml"/>
    </mappers>
</configuration>
  • 配置一个专门用来存放SQL语句的配置文件Mapper.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">
<mapper namespace="userSql">
    <!--namespace:命名空间-->
    <!--Sql语句在映射文件中集中管理:是将SQL和代码做解耦
        不同功能的SQL可以写在不同的映射文件里
        比如处理test_user表相关的业务SQL可以放在UserMapper.xml里
    -->
    <!--这条sql语句的编号:命名空间 + 当前这个标签的id-->
    <!--如果做查询,要写resultType,要写封装实例的全限定类名-->

    <!-- 每个标签都需要一个唯一的id属性:
         每一个标签的id不能重复(本Mapper文件中), 用来标识一条SQL  -->
    <!-- 在这个Mapper文件中, 怎么唯一表示SQL语句?
    namespace.id (命名空间.标签的id ) 是这个SQL语句的坐标  -->
    <!-- <insert> 插入标签 -->
    <!-- <delete> 删除标签 -->
    <!-- <update> 修改标签 -->
    <!-- <select> 查询标签 -->
    <!-- parameterType:参数的类型(可以省略,标准语法要指明 ) -->
    <!-- resultType:返回的结果集的类型(不能省略) -->

    <select id="selectById" resultType="com.coo1heisenberg.bean.User">
        select * from account where id = #{id}
    </select>
    <!--Mybatis中的占位符是:#{内容},不是?-->
</mapper>
  • 实现
@Data
public class User {
    Integer id;
    String name;
    Integer money;
}


public interface UserDao {
    public User selectUserById(Integer id);
}


/**
 * SqlSessionFactory:每一个Mybatis应用都是以SqlSessionFactory的实例对象为核心的。
 * 使用Mybatis必须以SqlSessionFactory的实例为核心,再以SqlSessionFactory的实例生产SqlSession实例对象的。
 *
 * SqlSession:这个其实表示和数据库之间的一个连接,里面封装了 Connection对象
 */
public class UserImpl implements UserDao{
    @Override
    public User selectUserById(Integer id){
        // 在映射文件中的编号:usersql.selectById
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

        User user = null;
        try {
            InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
            SqlSessionFactory sqlSessionFactory = builder.build(inputStream);

            // sql 会话,其实是对connection做了封装
            SqlSession sqlSession = sqlSessionFactory.openSession();

            // preparedStatement + setInt(1, id) + preparedStatement.executeQuery()
            // 然后将resultSet变成一个User实例
            user = sqlSession.selectOne("userSql.selectById", id);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return user;
    }
}

在上面的案例中MyBatis做了什么事情:

  • connection.preparedStatement需要传入的Sql语句,我们仅仅提供了坐标(映射文件的命名空间+id)
  • 参数和占位符的对应关系,自动对应起来
  • resultSet获得结果集,并且封装为User实例的过程完全是MyBatis自动完成的

Mybatis

Mybatis介绍

  • Mybatis是一个基于Java的持久层框架
  • Mybatis是一个ORM(Object Relationship Mapping)框架(对象关系映射框架)
    • Mybatis就是一个可以帮助我们把关系型数据库中的记录转化为Java对象把Java对象转化为关系型数据库中的记录的这么一个框架。
      • 类和表之间的关系(eg:User类和test_user表之间的关系)
      • 类中的成员变量和表中的列之间的关系(名称、JavaType和JdbcType)
      • 数据库中的一条记录和Java中的一个实例(比如一个user对象和test_user中的一条记录)
  • 支持自定义 SQL存储过程以及高级映射
    • Mybatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作
    • Mybatis 可以通过简单的XML或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录
  • Mybatis就是一个可以帮助我们在Java代码中更加高效的去操作数据库的一个框架

Mybatis的环境搭建

  1. 导包在pom.xml
<dependencies>
  <!--mybatis-->
  <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.9</version>
  </dependency>

  <!-- 数据库驱动包 -->
  <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
  </dependency>

<!-- 测试包 -->
  <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
  </dependency>
</dependencies>
  1. 配置MyBatis的主配置文件(mybatis-config.xml)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

<!-- 环境的配置,其实就是去配置数据库连接-->
<environments default="development">
<environment id="development">
  <transactionManager type="JDBC"/>
  <dataSource type="POOLED">
      <property name="driver" value="com.mysql.jdbc.Driver"/>
      <property name="url" value="jdbc:mysql://localhost:3306/xxx?useSSL=false&amp;characterEncoding=utf8"/>
      <property name="username" value="root"/>
      <property name="password" value="123456"/>
  </dataSource>
</environment>
</environments>

<!-- 去查找的Mapper文件 -->
<mappers>
<mapper resource="com/snow/www/mapper/AccountMapper.xml"/>
</mappers>

</configuration>
  1. 创建一个Java接口Mapper接口文件 (注意路径)
  2. 创建一个与Java接口文件对应的Mapper.xml配置文件

之后的步骤见上面的Mybatis的入门案例


动态代理

上面代码存在的一些不足:

  • 目前Mybatis使用起来还不够灵活,不够简单。
  • 虽然解决了SQL语句硬编码的问题,但是又出现了新的问题,SQL语句的坐标存在硬编码
  • sqlSession调用的方法需要我们自己去指定,也就是UserDaoImpl中的内容还不够通用,我们想要进一步干掉它

而Mybatis的动态代理可以帮助我们去生成接口的代理对象,我们可以自己不实现接口。

eg:

public class MyBatisUtil {
    // 线程安全的值,可以全局共享
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder().
                    build(Resources.getResourceAsStream("mybatis.xml"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSessionFactory getSqlSessionFactory() {
        return sqlSessionFactory;
    }
}



public class MybatisTest {
    @Test
    public void myTest() {
        // Mybatis生成的代理对象 -> 没有委托类 -> 只能从接口身上获得一些信息
        /**
         * 获得接口的全限定类名
         * 获得方法的数组 -> 方法的名称、返回值类型、参数的个数和类型
         * 需要一个sql语句在映射文件中的坐标 -> 能否从上面选择一些信息保证组合起来的坐标是唯一的
         * 坐标 = 接口的权限定类名 + 方法名(接口中的方法不允许重载)
         */
        SqlSessionFactory sqlSessionFactory = MyBatisUtil.getSqlSessionFactory();

        SqlSession sqlSession = sqlSessionFactory.openSession();

        UserDao userDao = sqlSession.getMapper(UserDao.class);

        User user = userDao.selectUserById(2);

        System.out.println(user);

    }
}

<?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">
<mapper namespace="com.coo1heisenberg.dao.UserDao">
    <!--namespace:命名空间-->
    <!--Sql语句在映射文件中集中管理:是将SQL和代码做解耦
        不同功能的SQL可以写在不同的映射文件里
        比如处理test_user表相关的业务SQL可以放在UserMapper.xml里
    -->
    <!--这条sql语句的编号:命名空间 + 当前这个标签的id-->
    <!--如果做查询,要写resultType,要写封装实例的全限定类名-->

    <!-- 每个标签都需要一个唯一的id属性:
         每一个标签的id不能重复(本Mapper文件中), 用来标识一条SQL  -->
    <!-- 在这个Mapper文件中, 怎么唯一表示SQL语句?
    namespace.id (命名空间.标签的id ) 是这个SQL语句的坐标  -->
    <!-- <insert> 插入标签 -->
    <!-- <delete> 删除标签 -->
    <!-- <update> 修改标签 -->
    <!-- <select> 查询标签 -->
    <!-- parameterType:参数的类型(可以省略,标准语法要指明 ) -->
    <!-- resultType:返回的结果集的类型(不能省略) -->

    <select id="selectUserById" resultType="com.coo1heisenberg.bean.User">
        /*不建议写select* */
        select id,name,money from account where id = #{id}
    </select>
    <!--Mybatis中的占位符是:#{内容},不是?-->
</mapper>

增删改查示例

    <!--增删改-->
    <!--insert、delete、update标签 id属性 对应的接口中的方法返回值都可以写int-->
    <insert id="insertUser">
        insert into account(id, name, money) values (#{id}, #{name}, #{money});
    </insert>

    <update id="updateUser">
        update account set name = #{name} where id = #{id};
    </update>

    <delete id="deleteById">
        delete from account where id = #{id};
    </delete>

对应接口:

int insertUser(User user);

int updateUser(String name, Integer id);

int deleteById(Integer id);

但是存在问题:Mybatis中openSession不提供事务的提交

事务

在使用Mybatis的时候, 自带事务,而且事务默认情况下是不会自动提交的

  • 解决方法一:执行完SQL语句之后, 使用sqlSession提交事务
    eg:sqlSession.commit();
  • 解决办法二: 执行完SQL语句之后, 使用sqlSession内部封装的Connection 提交事务
    eg:Connection conn = sqlSession.getConnection(); conn.commit();
  • 解决办法三(自动提交) :在获得SqlSession的时候,给sqlSessionFactory.openSession设置为真
    eg:SqlSession session = sqlSessionFactory.openSession(true);

Mybatis的配置

Mybatis的核心配置文件:

这些标签都是有序的,按下面排序
在这里插入图片描述

properties

properties表示可以外部配置的属性,并可以进行动态替换。(作为典型的是JDBC配置)

eg:

jdbc.properties文件中:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test_20240301?useSSL=false&userUnicode=true&characterEncoding=utf8
username=root
password=123456
在Mybatis_config.xml中的内容为:

<configuration>
<!-- 引入外部配置文件 -->
<properties resource="jdbc.properties" ></properties>
</configuration>

.....

<environments default="development">
       <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url"
                          value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
</environments>

settings

settings是MyBatis的行为配置(类似于idea和settings的关系)

eg:

日志的配置:

<configuration>
<settings>
   <!--  添加日志的配置,能够在控制台输出日志的 -->
   <setting name="logImpl" value="STDOUT_LOGGING"/>
	</settings>
</configuration>

其它一些settings配置:

<settings>
// 缓存
<setting name="cacheEnabled" value="true"/>
// 懒加载
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="safeResultHandlerEnabled" value="true"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
<setting name="defaultScriptingLanguage" value="org.apache.ibatis.scripting.xmltags.XMLLanguageDriver"/>
<setting name="defaultEnumTypeHandler" value="org.apache.ibatis.type.EnumTypeHandler"/>
<setting name="callSettersOnNulls" value="false"/>
<setting name="returnInstanceForEmptyRow" value="false"/>
<setting name="logPrefix" value="exampleLogPreFix_"/>
<setting name="logImpl" value="SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING"/>
<setting name="proxyFactory" value="CGLIB | JAVASSIST"/>
<setting name="vfsImpl" value="org.mybatis.example.YourselfVfsImpl"/>
<setting name="useActualParamName" value="true"/>
<setting name="configurationFactory" value="org.mybatis.example.ConfigurationFactory"/>
</settings>

typeAliases

typeAlies类型别名。(也就是我们可以对 类 起别名,简化操作) (暂时不建议使用)

eg:

<configuration>

 <!-- 类型别名 -->
 <typeAliases>
     <!-- alias别名 type全限定名 -->
     <typeAlias alias="account" type="com.snow.www.bean.Account"/>
     <typeAlias alias="user" type="com.snow.www.bean.User"/>
 </typeAliases>
</configuration>

则在Mapper.xml中的使用为:

// account == com.snow.www.bean.Account
<select id="selectAccountById"  resultType="account"> 
 select * from account where id = #{id}
</select>

environments

environments:可以配置成适应多种环境。比如开发环境、测试环境和生产环境等可能需要有不同的配置。

eg:

<!-- 环境的配置,其实就是去配置数据库连接-->
<environments default="development">

<!-- 环境的id,是唯一的-->
<environment id="development">

   <!-- 事务管理器
       JDBC:   使用JDBC连接来管理事务
       MANAGED: 把事务的管理交给外部的容器 -->
   <!-- 如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器,
				因为 Spring 模块会使用自带的管理器来覆盖前面的配置。-->
   <transactionManager type="JDBC"/>

   <!--
       POOLED: 使用Mybatis自带的连接池
       UNPOOLED:不使用连接池
       JNDI:使用外部的连接池  -->
   <dataSource type="POOLED">
       <property name="driver" value="${driver}"/>
       <property name="url" value="${url}"/>
       <property name="username" value="${username}"/>
       <property name="password" value="${password}"/>
   </dataSource>
</environment>
</environments>

mappers

这个是映射器的配置。配置mapper.xml配置文件。

  • 配置方式一:直接以对应mapper文件的相对路径

eg:

<configuration>    
<mappers>
     <mapper resource="com/snow/www/mapper/User.xml"/>
     <mapper url="file:///D:\javaee\....">
     <mapper class="com.coo1heisenberg.dao.UserDao">
 </mappers>
</configuration>
  • 配置方式二:配置某个包下的所有的配置文件

eg:

<configuration>   
<!--
        1. 接口和映射文件编译后要在同一级目录,并且同名
        2. 接口的全限定类名作为映射文件的命名空间
        3. 接口中的方法名(方法不允许重载)作为映射文件中的标签id(标签id不允许重复)
    -->
	<mappers>
        <package name="com.snow.www.mapper"/>
    </mappers>
</configuration>

输入映射

  • 输入映射其实就是在说Mybatis是如何传值的
  • 映射文件中的SQL语句中的语法:#{}里写什么东西,#{}这个位置最终在预编译的过程中变为了?
  • 在Mapper接口中,方法的形参写了什么样式(个数、类型、注解),最终在映射文件中该方法对应的sql语句中的#{}应该如何写

一个参数

一个参数:(基本类型、包装类、String)

  • #{任意值} 来取值: 不建议使用(显得不标准),建议使用注解写法
    • 虽然一个参数的时候, 可以在{}内部任意书写参数名, 这种乱写行为不好, 不要这么写

eg:

<select id="selectAccountById"  resultType="account">
  select * from account where id = #{xxx}
</select>
  • 如果在方法中 的一个参数加了@Param注解,那么 后面就只能通过 #{注解值} 来取值

eg:

// 查找
public Account selectAccountById2(@Param("id") Integer id);
<select id="selectAccountById2"   resultType="acc">
  select * from account where id = #{id}
</select>

多个参数

多个参数:需要注解指明#{注解值} 来取值

    1. 直接写多个值,用参数名简单匹配是不识别的
    1. 如果参数名简单匹配是不识别,又不想加注解,也是有别的解决手段(按位传值: 不建议), 但是建议加注解(最标准的写法)

eg:

List<Account> selectListByIdOrName(@Param("id") Integer id,@Param("name") String name);
<select id="selectListByIdOrName"   resultType="acc">
select * from account where id = #{id} or name = #{name}
</select>

按位置传值

按位传值:完全不建议(容易因为程序员的记忆和修改导致bug产生, 除非除了按位传值没办法了)

  • 方式一::arg0、arg1、arg2...
    • 下标从0开始
  • 方式二:param1、param2、param3...
    • 下标从1开始

eg:

userMapper.insertUser("zs", 18, "beijing");
方式一:
<insert id="insertUser">
   insert into `user`  set `name`=#{arg0}, age=#{arg1}, address=#{arg2}
</insert>

方式二:
<insert id="insertUser">
   insert into `user`  set `name`=#{param1}, age=#{param2}, address=#{param3}
</insert>

对象传值

  • 方式一:SQL使用的参数命名要和对象内部属性保持一致 (#{成员变量名} 来取值)

eg:

    // 对象传值,没有使用@Param注解,则是成员变量名
    int insert1(User user);
    <insert id="insert1">
        insert into account(id,name,money) values (#{id}, #{name} ,#{money})
    </insert>
  • 方式二:对象有注解,必须通过 #{注解值.成员变量名}来取值

eg:

    // 对象传值,使用@Param注解,则是@Param写了什么就用什么
    // user.money....
    int insert2(@Param("user") User user);
    <insert id="insert2">
       insert into account(id,name,money) values (#{user.id}, #{user.name}, #{user.money})
    </insert>

使用Map进行传值

  • 方式一:SQL使用的参数命名要和Map中存储数据的key保持一致 (#{key}来取值)

eg:

    // Map map = new HashMap();
    // map.put("id", 3);
    // map.put("name", "ss")
    // Map传值 --> 没有使用@Param注解 --> #{}里面写的是map的key:id和name
    int updateNameById(Map map);
    <update id="updateNameById">
        update account set name = #{name} where id = #{id}
    </update>
  • 方式二:Map对象有注解, 必须通过#{注解值.key}来取值

eg:

    // Map传值 --> 使用@Param注解 --> #{}里面写的是@Param注解的值 + map的key:map.id和map.name
    int updateNameById2(@Param("map") Map map);
    <update id="updateNameById2">
        update account set name = #{map.name} where id = #{map.id}
    </update>

小结
输入映射,Mybatis如何使用的user,通过get方法来使用。


#{}和${}的区别

  • 使用${}做的就是字符串的拼接,如果传入的是字符串,需要在${}外围手动增加单引号``
    • 核心点:使用${}有SQL注入的风险(SQL注入指:在执行的SQL语句之外额外执行一部分,导致信息泄露或者数据库被丢弃)
  • 使用#{}过程是预编译,不会有SQL注入的风险
  • #{参数}使用:预编译占位 (尽量使用 #{} ) PreparedStatement

eg:

    <insert id="insert1" >
        insert into account(id,name,money) values (#{id}, #{name} ,#{money})
    </insert>
/**
 * ==>  Preparing: insert into account(id,name,money) values (?, ? ,?)
 * ==> Parameters: 6(Integer), ss(String), 8000(Integer)
 * <==    Updates: 1
 */
  • ${参数}使用:字符串拼接, Statement (存在SQL注入问题)
    • 一般用在排序或者把表名传入的时候

eg:

    <insert id="insert3">
        insert into account(id,name,money) values (${id}, `${name}` ,`${money}`)
    </insert>
/**
 * ==>  Preparing: insert into account(id,name,money) values (5, `ws` ,`7000`)
 */

输出映射

  • 输出映射一定和查询有关系,一定对应的是select标签
  • 使用select标签一定使用和类型有关系的属性:
    • resultType
    • resultMap
    • resultType可以写别名

eg:

-- 只有1列,并且记录数为1条  → 查询user表中有多少条记录
-- 一个int或Integer类型的值来接收
select count(*) from account ;

-- 只有一列,结果的记录数为多条 → 查询年龄为xxx的用户的名称
-- 数组或List、Set
select name from account where age = 25;

-- 多列,结果的记录数为1条 → 查询id为某个值的用户的全部信息
-- 引用类型对象
select id,name,money from account where id = 2;

-- 多列,结果的记录数为多条 → 查询年龄为xxx的用户的全部信息
-- 引用类型对象的数组或List、Set
select id,name,money from account where age = 25 ;

综上可得

  • 选择何种封装类型:取决于结果集中的列的个数,以及结果的记录数
  • 封装最终体现在:落脚点在Mapper接口中的方法的返回值类型

一个参数

指的是:结果列为1且记录数为1(或0)

  • 一个参数: 必须要有resultType(写简单参数的全限定名称或者是内置的别名)

eg:

    // 单个列,结果记录数为1
    int selectCount();
    String selectNameById(Integer id);
    <select id="selectCount" resultType="java.lang.Integer">
        select count(*) from account;
    </select>
    <select id="selectNameById" resultType="java.lang.String">
        select name from account where id = #{id};
    </select>

多个参数

指的是:列只有一列,结果集中的记录数有多条(0或1条)

  • 指: 多个参数构成的数组/List/Set
  • 当我们返回多个简单参数的时候,在方法中定义的是数组就会返回数组,定义的是集合就会返回集合。
    • xml中的标签配置不需要改变。并且, resultType的值是单个记录的类型

eg:

    // 单个列,结果记录数为多条
    // 按照不同的类型来封装,但是SQL语句是一样的
    String[] selectNamesByMoney1(Integer money);
    List<String> selectNamesByMoney2(Integer money);
    Set<String> selectNamesByMoney3(Integer money);
    <select id="selectNamesByMoney1" resultType="java.lang.String">
        select name from account where money = #{money};
    </select>
    <select id="selectNamesByMoney2" resultType="java.lang.String">
        select name from account where money = #{money};
    </select>
    <select id="selectNamesByMoney3" resultType="java.lang.String">
        select name from account where money = #{money};
    </select>

单个对象

  • 核心点:查询结果集中的列名 要和 对象中的成员变量名(set方法)相同
  • 查询结果集中的列名可以通过as起别名的方式做修改

eg:

        User selectAllMember(Integer id);

        User user = userMapper.selectAllMember(2);
    <select id="selectAllMember" resultType="com.coo1heisenberg.bean.User">
        select * from account where id = #{id};
    </select>

多个对象

  • 多个对象:数组/List/Set
  • resultType的值是单个元素的类型

JDBC的封装举例:

ResultSet resultSet = prepareStatement.executeQuery();
List<User> users = new ArrayList<>();
while(resultSet.next()){
  User user = new User();
  user.setUsername(resultSet.getString("username"));
  user.setPassword(resultSet.getString("password"));
  users.add(user);
}
//如果你需要一个Set可以在第2行这里定义为一个set ,也可以将这个List转为一个Set
//如果你需要一个数组,也可以将这个List转为一个数组

eg:

// 多个列,结果记录数为多条
User[] selectByAge1(@Param("age") Integer age);

List<User> selectByAge2(@Param("age") Integer age);

Set<User> selectByAge3(@Param("age") Integer age);
<select id="selectByAge1" resultType="com.coo1heisenberg.demo2.bean.User">
select * from account
where age = #{age}
</select>

<select id="selectByAge2" resultType="com.coo1heisenberg.demo2.bean.User">
select * from account
where age = #{age}
</select>

<select id="selectByAge3" resultType="com.coo1heisenberg.demo2.bean.User">
select * from account
where age = #{age}
</select>

resultMap

  • resultMap:是用来做参数映射
  • 存在这样的对应关系,我们才知道从结果集拿那一列的值(resultSet.getString("列名")),获得的值要封装给哪一个成员变量
  • resultMap是可以复用的

eg:

UserVo selectUserVoByPrimaryKey(@Param("id") Integer id);

UserVo userVo = userMapper.selectUserVoByPrimaryKey(2);
System.out.println("userVo = " + userVo);
    <!--id属性:是要和select标签中的resultMap属性建立联系-->
    <!--type属性:写的是要封装的对象的全限定类名(或别名)-->
    <resultMap id="userVoMap" type="com.coo1heisenberg.bean.UserVo">
        <!--查询结果集中的列名要和成员变量名建立映射关系-->
        <id property="id" column="id"></id>
        <result property="money" column="money"></result>
        <result property="name" column="name"></result>
    </resultMap>
    <!--resultMap属性中写的是引用的resultMap标签的id-->
    <select id="selectUserVoByPrimaryKey" resultMap="userVoMap">
        select * from account where id = #{id};
    </select>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/482627.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

笔记1-Hadoop之HDFS

Hadoop 开源版本的HADOOP和其他框架的对应关系很混乱&#xff0c;要注意。 Hadoop四大模块&#xff1a;Common HDFS MapReduce Yarn Hadoop能对大量的数据进行分布式处理&#xff0c;可以轻松的从一台服务器扩展到千台服务器&#xff0c;并且 每一台服务器都能进行本地计算和…

Flutter开发进阶之瞧瞧BuildOwner

Flutter开发进阶之瞧瞧BuildOwner 上回说到关于Element Tree的构建还缺最后一块拼图&#xff0c;build的重要过程中会调用_element!.markNeedsBuild();&#xff0c;而markNeedsBuild会调用owner!.scheduleBuildFor(this);。 在Flutter框架中&#xff0c;BuildOwner负责管理构建…

【ai技术】(4):在树莓派上,使用qwen0.5b大模型+chatgptweb,搭建本地大模型聊天环境,速度飞快,非常不错!

1&#xff0c;视频地址 https://www.bilibili.com/video/BV1VK421i7CZ/ 2&#xff0c;下载镜像 raspberry-pi-os-64-bit https://blog.csdn.net/freewebsys/article/details/136921703 项目地址&#xff1a; https://www.raspberrypi.com/software/operating-systems/#rasp…

【JAVA重要知识 | 第九篇】ConCurrentHashMap源码分析

文章目录 9.ConCurrentHashMap源码分析9.1 ConCurrentHashMap 1.79.1.1存储结构9.1.2初始化9.1.3put流程&#xff08;1&#xff09;判断是否要put(key,value)流程&#xff08;2&#xff09;put(key,value)&#xff08;3&#xff09;自旋获取hash位置的HashEntry 9.1.4 rehash扩…

【力扣hot100】1. 两数之和 49.字母异位词分组 128. 最长连续序列

目录 1. 两数之和题目描述做题思路参考代码 49.字母异位词分组题目描述做题思路参考代码 128. 最长连续序列题目描述做题思路参考代码 1. 两数之和 题目描述 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数…

子网掩码,网段,网关

IP地址、子网掩码、网段、网关【网络常识 2】_哔哩哔哩_bilibili 网关&#xff1a; 什么时候需要用到网关&#xff1a; 若目标IP在同一网段则可以直接通信不需要经过网关&#xff0c;否则需要。 怎么判断对方的ip是否与我在同一网段呢&#xff1f; 判断网络号是否相同。 电…

Android Studio 和 lombok 的版本适配、gradle依赖配置、插件安装及使用

文章目录 Intro注意事项Android Studio 和 lombok 的版本选择及下载下载链接 在 Android Studio 中安装一次 lombok 插件在每个 gradle 项目中添加 lombok 相关依赖(如要用到)使用ref Intro 用惯了 JavaMavenIDEA 开发后端服务&#xff0c;突然有一天用 JavaGradleAndroidStud…

【Flink】窗口实战:TUMBLE、HOP、SESSION

窗口实战&#xff1a;TUMBLE、HOP、SESSION 1.TUMBLE WINDOW1.1 语法1.2 标识函数1.3 模拟用例 2.HOP WINDOW2.1 语法2.2 标识函数2.3 模拟用例 3.SESSION WINDOW3.1 语法3.2 标识函数3.3 模拟用例 4.更多说明 在流式计算中&#xff0c;流通常是无穷无尽的&#xff0c;我们无法…

【PyQt】17.1-日历控件 不同风格的日期和时间、以及高级操作

日历控件puls版本 前言一、日历控件中不同风格的日期和时间1.1 代码1.2 注意事项格式设置m的大小写问题QTime和QDateTime的区别 1.3 运行结果 二、高级操作2.1 成倍调整2.2 下拉出日历2.3 事件函数2.4 获取设置的日期和时间 完整代码 前言 1、不同风格的日期和时间展示 2、高级…

Codeforces Round 930 (Div. 2)(A,B,C,D)

比赛链接 C是个交互&#xff0c;D是个前缀和加二分。D还是很难写的。 A. Shuffle Party 题意&#xff1a; 您将得到一个数组 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1​,a2​,…,an​ 。最初&#xff0c;每个 1 ≤ i ≤ n 1 \le i \le n 1≤i≤n 对应 a i i a_ii…

深度学习十大算法之长短时记忆网络(LSTM)

一、长短时记忆网络&#xff08;LSTM&#xff09;的基本概念 长短时记忆网络&#xff08;LSTM&#xff09;是一种特殊类型的循环神经网络&#xff08;RNN&#xff09;&#xff0c;主要用于处理和预测序列数据的任务。LSTM由Hochreiter和Schmidhuber于1997年提出&#xff0c;其…

41-Vue-webpack基础

webpack基础 前言什么是webpackwebpack的基本使用指定webpack的entry和output 前言 本篇开始来学习下webpack的使用 什么是webpack webpack: 是前端项目工程化的具体解决方案。 主要功能&#xff1a;它提供了友好的前端模块化开发支持&#xff0c;以及代码压缩混淆、处理浏览…

海康威视-AIOT的业务转型

海康威视的转型和定位为智能物联网&#xff08;AIoT&#xff09;解决方案和大数据服务的提供商。 公司不仅仅聚焦于其核心的视频监控业务&#xff0c;而且正在积极拓展到新的技术领域和市场。通过专注于物联感知、人工智能、大数据等技术的创新&#xff0c;对未来技术发展方向的…

golang import引用项目下其他文件内函数

初始化项目 go mod init [module名字] go mod init project 项目结构 go mod 文件 代码 需要暴露给外界使用的变量/函数名必须大写 在main.go中引入&#xff0c;当前项目模块名/要引用的包名 package mainimport (// 这里的路径开头为项目go.mod中的module"project/…

微信小程序----猜数字游戏.

目标&#xff1a;简单猜字游戏&#xff0c;系统随机生成一个数&#xff0c;玩家可以猜8次&#xff0c;8次未猜对&#xff0c;游戏结束&#xff1b;未到8次猜对&#xff0c;游戏结束。 思路和要求&#xff1a; 创建四个页面&#xff0c;“首页”&#xff0c;“开始游戏”&#…

hadoop基本概念

一、概念 Hadoop 是一个开源的分布式计算和存储框架。 Hadoop 使用 Java 开发&#xff0c;所以可以在多种不同硬件平台的计算机上部署和使用。其核心部件包括分布式文件系统 (Hadoop DFS&#xff0c;HDFS) 和 MapReduce。 二、HDFS 命名节点 (NameNode) 命名节点 (NameNod…

STM32 | Systick定时器(第四天)

STM32 第四天 一、Systick定时器 1、定时器概念 定时器:是芯片内部用于计数从而得到时长的一种外设。 定时器定时长短与什么有关???(定时器定时长短与频率及计数大小有关) 定时器频率换算单位:1GHZ=1000MHZ=1000 000KHZ = 1000 000 000HZ 定时器定时时间:计数个数…

Django缓存(二)

一、视图缓存 Django的缓存可以设置缓存指定的视图,具体方式使用django.views.decorators.cache.cache_page, 方法有2种方式: 装饰器:以方法以装饰器的方式使用 from django.views.decorators.cache import cache_page@cache_page(60 * 15,cache="default") def…

CRC计算流程详解和FPGA实现

一、概念 CRC校验&#xff0c;中文翻译过来是&#xff1a;循环冗余校验&#xff0c;英文全称是&#xff1a;Cyclic Redundancy Check。是一种通过对数据产生固定位数的校验码&#xff0c;以检验数据是否存在错误的技术。 其主要特点是检错能力强、开销小&#xff0c;易于电路实…

【prompt六】MaPLe: Multi-modal Prompt Learning

1.motivation 最近的CLIP适应方法学习提示作为文本输入,以微调下游任务的CLIP。使用提示来适应CLIP(语言或视觉)的单个分支中的表示是次优的,因为它不允许在下游任务上动态调整两个表示空间的灵活性。在这项工作中,我们提出了针对视觉和语言分支的多模态提示学习(MaPLe),以…