Mybatis-基本学习(下)

四,MAP的使用--超常用

思考:如何简化parameterType?总不能每次加个@Param对应值把?

使用场景?
类似加了一层封装

  • 实体类,或者数据库中的表,字段或者参数过多,就考虑使用Map
  • 非常灵活,不用死死的在方法中定一个值,然后最后处理一个值的锁定。。。它可以随意定义几个值的锁定(前提是sql语句有对应)

HashMap<> 因为要调用hashcode()方法和equals()方法,进行比较,,,所以不能为基本类型

规范? -满足pojo的类型,SQL值的需求- Map需要<XX,Object>,因为Object通配所有,毕竟有Integer Double String……
使用时要---parameterType="map"

使用的依据:

  • 本质上parameterType就是一个送参数的,不管你送啥,你要将下面的值和sql以后要使用的参数对应就好
  • 最后送参时还是要对应原本的类型的,只是使用容器作为一个中介

考虑,能否使用ArrayList---答:能 比较麻烦,没有map直接--未考虑好

注意:因为map只是送值的,所以只有put操作。。

  • value分不分类型? 插入时不分,锁定值时区分 ---(最好对应-)map.put("id",8);

操作

  • 1.接口中
    // map的使用---万能的Map
    int addUser1(Map<String,Object> map);
    
    User  getUserById1(Map<String,Object> map);  // map 用法
    
    
  • 2.Mapper.xml中
    <!--map的使用-->
    <insert id="addUser1" parameterType="map">
        insert into  mybatis.user(id,name,password) values (#{userId},#{userName},#{userPassword});
    </insert>
    
        <select id="getUserById1" parameterType="map" resultType="com.zjz.pojo.User">
        select * from mybatis.user where id = ${id}
    </select>
  • 3.Test
    @Test
    public void TestAddUser1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

         Map<String, Object> map = new HashMap<>();
        map.put("userId",5);       // 对应#{userId}--类型限制POJO
        map.put("userName","zjz5");   // 对应#{userName}--类型限制POJO
        map.put("userPassword","321616");  // 对应#{UserPassword}--类型限制POJO
        mapper.addUser1(map);

        // 提交事务
        sqlSession.commit();

        sqlSession.close();

    }
    
    
        @Test
    public void TestGetUserById1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        Map<String, Object> map = new HashMap<>();
        map.put("id","8");
        User userById1 = mapper.getUserById1(map);
        System.out.println(userById1);

        sqlSession.close();

    }
    

使用详情及规范

  • 类型限制(POJO),值对应(SQL)
  • 方法只使用 put 送值-,
  • value类型没对应好,。value分不分类型? 插入时不分,锁定值时区分 ---(最好对应-)map.put("id",8);
  • key没对应好,如果送的值多了,报错---少了,送null --(主键不送---肯定报错啊!)
    • 注:查询时必须都得对应上key

不懂的---两个例子,你自己做一个,三列即可确定一件事了

  • 备注:HashMap<> 因为要调用hashcode()方法和equals()方法,进行比较,,,所以不能为基本类型

问题以及双锁定条件

根据 密码 和 名字 查询用户

  • 思路一:直接在方法中传递参数

      1. 在接口方法的参数前加 @Param属性
    • ------为啥需要@Param,不加时,直接报错,因为类型影响后面
      1. Sql语句编写的时候,直接取@Param中设置的值即可,不需要单独设置参数类型(parameterType)
        //通过密码和名字查询用户 
        User selectUserByNP(@Param("username") String username,@Param("pwd") String pwd);
        
        
         /* <select id="selectUserByNP" resultType="com.kuang.pojo.User"> 
         select * from user where name = #{username} and pwd = #{pwd} 
         </select> */
    
    
  • 思路二:使用万能的Map

      1. 在接口方法中,参数直接传递Map;
      1. 编写sql语句的时候,需要传递参数类型,参数类型为map
      1. 在使用方法的时候,Map的 key 为 sql中取的值即可,没有顺序要求!
        User selectUserByNP2(Map<String,Object> map);
        
        
        <select id="selectUserByNP2" parameterType="map" resultType="com.kuang.pojo.User"> 
        select * from user where name = #{username} and pwd = #{pwd} 
        </select>
        
        Map<String, Object> map = new HashMap<String, Object>(); 
          map.put("username","小明"); 
          map.put("pwd","123456"); 
        User user = mapper.selectUserByNP2(map);
    
  • 总结:

    • 如果参数过多,我们可以考虑直接使用Map实现,如果参数比较少,直接传递参数即可

@Param注解

1.使用@Param

  • 实例一 @Param注解单一属性

      // 依据id,name查询
      User getUserByIdName(@Param("id") int id,@Param("name") String name);
    -------------------------------------
     <select id="getUserByIdName" resultType="com.zjz.pojo.User">
          select * from mybatis.user where id = #{id} AND name = #{name}
      </select>
    
  • 1.当你使用了使用@Param注解来声明参数时,如果使用 #{} 或 ${} 的方式都可以。

  // 根据id查询
  User getUserById(@Param("id")int id);
  
  <select id="getUserById" parameterType="int" resultType="com.zjz.pojo.User">
        select * from mybatis.user where id = ${id}
    </select>
  • 2.当你不使用@Param注解来声明参数时,必须使用 #{}方式且只有一个参数。在我的版本(M361,S802) ${} 的方式,不会报错。(可能其它版本报错)
  • 所以目前还是单个参数可以不用,多个参数要用
  // 根据id查询
  User getUserById(int id);
  
  <select id="getUserById" parameterType="int" resultType="com.zjz.pojo.User">
        select * from mybatis.user where id = ${id}
    </select>

2,不使用@Param注解

  • 不使用@Param注解时,参数只能有一个,可以是属性,也可以是对象
    • 目前似乎不支持@param("User")
      • 目前也没有此限制--并且是Javabean。在SQL语句里可以引用JavaBean的属性,而且只能引用JavaBean的属性。
    
      // 插入insert
      int addUser(User user);
      
        <insert id="addUser" parameterType="com.zjz.pojo.User">
          insert into  mybatis.user(id,name,password) values (#{id},#{name},#{password});
      </insert>
    
     @Test
      public void TestAddUser(){
          SqlSession sqlSession = MybatisUtils.getSqlSession();
          UserMapper mapper = sqlSession.getMapper(UserMapper.class);
           mapper.addUser(new User(4, "zjz4", "123456"));
          // 提交事务
          sqlSession.commit();
          sqlSession.close();
    
      }
    
    

小结:

  • 所有的增删改操作都需要提交事务!
  • 接口所有的普通参数,尽量都写上@Param参数,尤其是多个参数时,必须写上!(否则报错)
  • 有时候根据业务的需求,可以考虑使用map传递参数!
  • 为了规范操作,在SQL的配置文件中,我们尽量将Parameter参数和resultType都写上!

五.配置解析

1.核心配置文件

  • mybatis-config.xml
configuration(配置)
  properties(属性)
  settings(设置)
  typeAliases(类型别名)
  typeHandlers(类型处理器)
  objectFactory(对象工厂)
  plugins(插件)
  environments(环境配置)
    environment(环境变量)
      transactionManager(事务管理器)
      dataSource(数据源)
  databaseIdProvider(数据库厂商标识)
  mappers(映射器)
  <!-- 注意元素节点的顺序!顺序不对会报错 -->

2.environments元素

配置MyBatis的多套运行环境,将SQL映射到多个不同的数据库上,必须指定其中一个为默认运行环境(通过default指定)

默认 事务JDBC 数据源 POOLED

  • 1.子元素节点:environment

    • 具体的一套环境,通过设置id进行区别,id保证唯一!
    • 子元素节点:transactionManager - [ 事务管理器 ]
    • ` ` 有**两个事务管理器**,不是一个!!
  • 2.子元素节点:数据源(dataSource)

    • dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
    • 数据源是必须配置的。
    • 有三种内建的数据源类型
    • type="[UNPOOLED|POOLED|JNDI]") ---JNDI 正常连接
    • (池:用完可以回收,不关,等下一个来连)
  • 3.属性(properties)

    • 使用它实现引用配置文件

    • 优先走外部的,再走里面的property

           <!--引入外部配置文件-->
          <properties resource="db.properties">
              <property name="username" value="root"/>
              <property name="password" value="123456"/>
          </properties>
      
      
  • 4.别名(typeAliases)

  • 1.起别名typeAlias

      <!--起别名-->
        <typeAliases>
            <typeAlias type="com.zjz.pojo.User" alias="User"/>
        </typeAliases>
    
    
      // 这样在XXXMapper.xml中的resultType就可以直接使用User,不用com.zjz.pojo.User
    
      <select id="getUserList" resultType="User" >
            select * from user
        </select>
    
    
    
  • 2.package(重要)

  • 扫描包下的实体类,将类名首字母小写作为别名-----

  • 可以自定义DIY --- 注解@Alias

    <!--起别名-->
    <typeAliases>
        <package name="com.zjz.pojo"/>
    </typeAliases>
  
  
    非必须:javabean 注解 
    @Alias("xiaoming")
  
  • 两个之间的区别
    • Aliases 可以之间手动DIY一个别名
    • package 需要找到对应的javaBean,注解 ,然后就DIY的,否则都是类名首字母小写

设置

  • setting

  • 一个配置完整的 settings 元素的示例如下:

        <settings>
            <setting name="cacheEnabled" value="true"/>      <!--开关映射器配置文件中已配置的任何缓存-->
            <setting name="lazyLoadingEnabled" value="true"/>  <!--延迟加载的全局开关。-->
            <setting name="multipleResultSetsEnabled" value="true"/> <!--是否允许单个语句返回多结果集(需要数据库驱动支持)-->
            <setting name="useColumnLabel" value="true"/>              <!--使用列标签代替列名-->
            <setting name="useGeneratedKeys" value="false"/>          <!--允许 JDBC 支持自动生成主键,需要数据库驱动支持-->
            <setting name="autoMappingBehavior" value="PARTIAL"/>       <!--允许 JDBC 支持自动生成主键,需要数据库驱动支持-->
              <!--NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)-->
            <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/> <!--指定发现自动映射目标未知列(或未知属性类型)的行为。-->
              <!-- NONE: 不做任何反应
                WARNING:  WARNING 输出警告日志('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日志等级必须设置为 WARN)
               FAILING:  FAILING 映射失败 (抛出 SqlSessionException) -->
            <setting name="defaultExecutorType" value="SIMPLE"/>          <!--配置默认的执行器。SIMPLE 就是普通的执行器;-->
            <setting name="defaultStatementTimeout" value="25"/>         <!--设置超时时间-->
            <setting name="defaultFetchSize" value="100"/>           <!--为驱动的结果集获取数量(fetchSize)设置一个建议值。此参数只可以在查询设置中被覆盖。-->
            <setting name="safeRowBoundsEnabled" value="false"/>      <!--禁止在嵌套语句中使用结果处理器(ResultHandler) true开启禁止-->
            <setting name="mapUnderscoreToCamelCase" value="false"/>   <!--是否开启驼峰命名自动映射,
                 即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。注:ORACLE数据库常见-->
            <setting name="localCacheScope" value="SESSION"/>      <!--MyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。-->
            <setting name="jdbcTypeForNull" value="OTHER"/>          <!--当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型-->
            <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/> <!--指定对象的哪些方法触发一次延迟加载-->
            </settings>
    
    
  • 其它配置

  • 类型处理器 typeHandlers

  • 对象工厂 objectFactory

  • plugins 插件

    • mybatis-generator-core
    • mybatis-plus-----以后学
    • 通用mapper

映射(mapper)

  • MapperRegistry:注册绑定我们的配置文件
  • 方式一 resource(推荐使用)
  <!--每一个mapper.xml都需要在mybatis核心配置文件中注册-->

  <mappers>
      <mapper resource="com/zjz/dao/UserMapper.xml"/>
  </mappers>
  • 方式二 使用class文件绑定注册
  <!--每一个mapper.xml都需要在mybatis核心配置文件中注册-->
  <mappers>
      <mapper class="com.zjz.dao.UserMapper"/>
  </mappers>
  • class使用注意:
    • 接口必须和他的Mapper配置文件必须同名
    • 接口和他的配置文件必须在同一个包下
  <environments default="test">    <!--使用test环境-->
      <environment id="development">
          <!-- 事务管理-->
          <transactionManager type="JDBC"/>
          <dataSource type="POOLED">
              <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
              <property name="url"
                        value="jdbc:mysql://localhost:3306/mybatis? useSSL=true&useUnicode=true&characterEncoding=utf8"/>
              <property name="username" value="root"/>
              <property name="password" value="123456"/>
          </dataSource>
      </environment>


      <environment id="test">
          <!-- 事务管理-->
          <transactionManager type="JDBC"/>
          <dataSource type="POOLED">
              <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
              <property name="url"
                        value="jdbc:mysql://localhost:3306/mybatis? useSSL=true&useUnicode=true&characterEncoding=utf8"/>
              <property name="username" value="root"/>
              <property name="password" value="123456"/>
          </dataSource>
      </environment>

  </environments>

生命周期和作用域

  • 作用域(Scope)和生命周期
  • 理解我们目前已经讨论过的不同作用域和生命周期类是至关重要的,因为错误的使用会导致非常严重的并发问题。

  • SqlSessionFactoryBuilder:

    • 一旦创建了SqlSessionFactor,就不再需要了
    • 局部变量
  • SqlSessionFactory:

    • 生命周期就同于 MyBatis 的应用周期。
    • 可以想象为:数据库连接池
    • 一旦创建了 SqlSessionFactory,就要长期保存它,直至不再使用MyBatis 应用
    • 往往希望 SqlSessionFactory 作为一个单例,让它在应用中被共享。所以说 SqlSessionFactory 的最佳作用域是应用作用域。
  • SqlSession

    • 连接到连接池的请求
    • SqlSession 就相当于一个数据库连接(Connection 对象),你可以在一个事务里面执行多条 SQL,
      然后通过它的 commit、rollback等方法,提交或者回滚事务。
    • 所以它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给 SqlSessionFactory,
      否则数据库资源就很快被耗费精光,系统就会瘫痪,所以用 try...catch...finally... 语句来保证其正确关闭

ResultMap

属性名,字段名不一致

  • 如果POJO同数据库的字段不一致

  • 正常运行会显示不一致的字段为null
    User{id=0, name='zjz0', pwd='null'}

  • 1.解决方法--别名

    <select id="selectUserById" resultType="User">
         select id , name , password as pwd  from user where id = #{id}
     </select>
    
  • 2.方案二:使用结果集映射->ResultMap 【推荐】

    • 注意:<resultMap id="UserMap" type="User"> 的id
      对应 <select id="selectUserById" resultMap="UserMap">的resultMap
      <resultMap id="UserMap" type="User">
         <!-- id为主键 --> 
            <id column="id" property="id"/> 
        <!-- column是数据库表的列名 , property是对应实体类的属性名 -->
          <result column="name" property="name"/> 
           <result column="pwd" property="password"/>
     </resultMap> 
    
    
    <select id="selectUserById" resultMap="UserMap"> 
       select id , name , pwd from user where id = #{id}
     </select>
    
    
    
  • 数据库中,存在一对多,多对一的情况,我们之后会
    使用到一些高级的结果集映射,association,collection这些

多表查询

  • 在Mybatis-常规操作中 代码地址如下:在mybatis-06中

代码地址

posted @ 2021-09-14 06:20  狂哲  阅读(318)  评论(0编辑  收藏  举报