• MyBatis学习二


    1.   MyBatis 介绍

    • 1.  MyBatis SQL参数传递(掌握)
    • 2.  (多对一)关联映射(掌握)
    • 3. (一对多,多对多)集合映射(掌握)
    • 4.  SQL映射器Mapper(掌握)
    • 5. SSM集成(掌握)
    1. MyBatis SQL参数传递

    #{OGNL表达式} 和 ${OGNL表达式} 的区别

    2.1.  #{OGNL表达式}

    MyBatis会把这个表达式使用?(占位符)替换,作为一个sql参数使用

         比如name的值为: 

         定义SQL: select * from t_user where name = #{name}

         最终SQL: select * from t_user where name = ?

    2.2.  ${OGNL表达式}

    MyBatis会把这个表达式的值替换到sql中,作为sql的组成部分;

    该方式主要用于程序拼接SQL;

         比如name的值为:  '1  or 1=1'

         定义SQL: select * from t_user where name = ${id}

         最终SQL: select * from t_user where name = 1 or 1=1 出现sql注入

     

    如果sql中使用${OGNL},并且参数的类型是(integer,string....)那么OGNL表达式可以写成任意东西;

    2.3.  Sql注入

    预防sql注入,使用占位符查询

    select * from employee where username=? and password=?

    select * from employee where username='admin' and password='admin'

    字符串拼接,出现sql注入

    select * from employee where username='admin' and password='0000' or '1'='1'

    2.4.  ${OGNL}表达式的应用场景:不能用在登录场景,会出现sql注入

    用在order by 的场景

    Map<String,Object> 

    map.put("orderBy",'name desc');

    map.put("begin",0);

    map.put("end",10);

     

    在jdbc的sql代码order by后面不能使用占位符?,只能进行字符串的拼接

    2.5.  复杂参数传递  

     

    1. (多对一)关联映射

    3.1.  导入sql文件

     

     

    CREATE TABLE `t_dept` (

     `id` bigint(20) NOT NULL AUTO_INCREMENT,

     `name` varchar(255) DEFAULT NULL,

     PRIMARY KEY (`id`)

    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

     

    CREATE TABLE `t_user` (

     `id` bigint(20) NOT NULL AUTO_INCREMENT,

     `name` varchar(255) DEFAULT NULL,

     `password` varchar(255) DEFAULT NULL,

     `dept_id` bigint(20) DEFAULT NULL,

     PRIMARY KEY (`id`),

     KEY `fk1` (`dept_id`),

     CONSTRAINT `fk1` FOREIGN KEY (`dept_id`) REFERENCES `t_dept` (`id`)

    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    3.2.  建立Dept、User的模型

     

    3.3.  配置文件MyBatis-Config.xml

    <!-- 单向多对一 -->

    <mapper resource="cn/itsource/mybatis/day2/_1_manytoone/DomainMapper.xml" />

    3.4.  映射文件DomainMapper.xml

    <mapper namespace="cn.itsource.mybatis.day2._1_manytoone.DomainMapper">

     

             <!-- 保存部门 -->

             <insert id="saveDept" parameterType="cn.itsource.mybatis.day2._1_manytoone.Dept" useGeneratedKeys="true"

                      keyProperty="id">

                      insert into t_dept(name) values(#{name})

             </insert>

             <!-- 保存用户 -->

             <insert id="saveUser" parameterType="cn.itsource.mybatis.day2._1_manytoone.User" useGeneratedKeys="true"

                      keyProperty="id">

                      insert into t_user(name,password,dept_id) values(#{name},#{password},#{dept.id})

             </insert>

     

    </mapper>

    3.5.  保存测试数据

    String NAME_SPACE = "cn.itsource.mybatis.day2._1_manytoone.DomainMapper";

     

    @Test

    public void testSave() {

             SqlSession session = MyBatisUtils.getSession();

             // 先保存部门

             Dept dept1 = new Dept();

             dept1.setName("部门1");

             Dept dept2 = new Dept();

             dept2.setName("部门2");

             session.insert(NAME_SPACE + ".saveDept", dept1);

             session.insert(NAME_SPACE + ".saveDept", dept2);

     

             // 在保存用户

             for (int i = 1; i < 11; i++) {

                      User user = new User();

                      user.setName("user" + i);

                      user.setPassword("admin");

                      if (i % 2 == 0) {

                               user.setDept(dept1); // insert into t_user(dept_id) values(#{dept.id})

                      } else {

                               user.setDept(dept2);

                      }

                      session.insert(NAME_SPACE + ".saveUser", user);

             }

     

             session.commit();

             session.close();

    }

    3.6.  2个表关联查询的方式

    3.6.1.   单表查询,不能查询部门的名称

    select * from t_user

    3.6.2.   等值连接

    select u.*,d.*

    from t_user u,t_dept d

    where u.dept_id=d.id

    3.6.3.   内连接

    select u.*,d.*

    from t_user u

    join t_dept d

    on u.dept_id=d.id

    3.6.4.   左外连接

    select u.*,d.*

    from t_user u

    left join t_dept d

    on u.dept_id=d.id

    3.7.  MyBatis提供两种方式处理我们关联对象,嵌套查询和嵌套结果。

     

    3.8.  测试getAll方法

    @Test

    public void testGetAll() {

             SqlSession session = MyBatisUtils.getSession();

             List<User> list = session.selectList(NAME_SPACE + ".getAll");

             for (User user : list) {

                      System.out.println(user);

                      System.out.println(user.getDept());

             }

             session.close();

    }

    3.9.  嵌套结果(发一条左外连接sql解决问题,映射文件Mapper结果的手动封装ResultMap)

    使用嵌套结果映射来处理重复的联合结果的子集。--这种方式,所有属性都要自己来!!

     

    <!-- 嵌套结果(发一条左外连接sql解决问题,映射文件Mapper结果的手动封装ResultMap) -->

    <select id="getAll" resultMap="userResultMap">

             select u.id,u.name,u.password,d.id did,d.name dname

             from t_user u

             left join t_dept d

             on u.dept_id=d.id

    </select>

     

    <resultMap type="cn.itsource.mybatis.day2._1_manytoone.User" id="userResultMap">

             <!-- 多方User的id -->

             <id property="id" column="id" />

             <!-- 多方User的属性 -->

             <result property="name" column="name" />

             <result property="password" column="password" />

             <!-- 一方Dept的id和属性 -->

             <association property="dept" javaType="cn.itsource.mybatis.day2._1_manytoone.Dept">

                      <!--一方Dept的id -->

                      <id property="id" column="did" />

                      <!--一方Dept的属性 -->

                      <result property="name" column="dname" />

             </association>

    </resultMap>

    3.10.         嵌套查询(发1查询user+N查询dept条sql解决问题,映射文件Mapper结果的自动封装ResultMap)

    通过执行另外一个SQL映射语句来返回预期的复杂类型。

        <association ...>

    <association ...>

     

    select * from t_department where id = #{id}

     

     

    1. (一对多,多对多)集合映射

    4.1.  常见的关系

    员工和部门:

       在部门方,需要查询到当前部门下的所有员工。----集合查询

     

    一个部门  拥有   多个员工

     

    学生和课程

    多  对  多

     

    一个学生   可以学习    多门课程

    一门课程   可以有      多个学生

    4.2.  collection

    <collection property="集合数据" ofType="集合中元素类型">

      

    </collection>

     

    4.3.  嵌套结果(一条sql)

    嵌套查询在crm项目里面再讲

    <mapper namespace="cn.itsource.mybatis.day2._3_onetomany.DomainMapper">

             <!-- 嵌套结果(发一条左外连接sql解决问题,映射文件Mapper结果的手动封装ResultMap) -->

             <select id="getAll" resultMap="deptResultMap">

                      select d.id,d.name,u.id uid,u.name uname,u.password

                      from t_dept d

                      left join t_user u

                      on d.id=u.dept_id

             </select>

     

             <resultMap type="cn.itsource.mybatis.day2._3_onetomany.Dept" id="deptResultMap">

                      <!-- 处理一方 -->

                      <id property="id" column="id" />

                      <result property="name" column="name" />

                      <!-- 处理多方 -->

                      <!-- // 单向一对多 -->

                      <!-- private Set<User> users = new HashSet<User>(); -->

                      <collection property="users" javaType="cn.itsource.mybatis.day2._3_onetomany.User">

                               <id property="id" column="uid" />

                               <result property="name" column="uname" />

                               <result property="password" column="password" />

                      </collection>

             </resultMap>

    </mapper>

    1. 嵌套结果和嵌套查询的使用场景

    5.1.  嵌套结果:一条sql

    用在多对一的表结构

    多个数据字典明细和一个数据字典类型

    多个员工属于一个部门

    多个部门有一个部门经理

    5.2.  嵌套查询:1+n条sql

    用在一对多或者多对多的表结构

    展示数据的时候,在一行第一列显示一方,第二列显示多个多方,

    一对多:

    部门1   员工1。。。员工n

    多对多:

    员工1   角色1。。。角色n

    1. SQL映射器Mapper

    MyBatis基于代理机制,可以让我们无需再编写Dao的实现。

    6.1.  传统Dao接口,现在名称统一以Mapper结尾

     

    6.2.  接口实现方式一(传统)

     

    6.3.  接口实现方式二(映射器):

     

    6.4.  实现步骤

    6.4.1.   根据需求,创建模型相关的Mapper接口(UserMapper)

    6.4.2.   编写映射文件

    1. Mapper。Xml的命名空间,必须和接口的“全限定类名”一致
    2. 定义sql标签的id,需要和“接口的方法”一致,参数一致,返回值一致
    3. 缓存

    7.1.  默认支持一级缓存,二级缓存需要配置,同JPA一致

    缓存是一种典型的“以空间换时间”的策略。

    7.2.  一级缓存

        SqlSession级别缓存,缓存对象存储周期为第一次获取,到sqlsession被销毁掉,或是sqlSession().clearCache();

    7.3.  二级缓存

        SqlSessionFactory级别缓存,缓存对象存储周期为第一次获取,到SqlSessionFactory被销毁掉(应用停止了);

    默认情况下,只开启一级缓存,如果需要开启二级缓存我们需要在Mapper.xml添加一个<cache>标签和在主配置文件中<setting name="cacheEnabled" value="true"/>;

    1.    注意:需要缓存的对象,应该实现java.io.Serializable;

       

    1. SSM集成

    如果要做三大框架集成,我们先保证在一个项目,每一个框架都能够独立运行!!

    8.1.  集成SpringMvc

    8.1.1.   导入21个jar文件(包含spring的jar)

    aop,tx,jdbc,web,webmvc

    dbcp,fileupload,jackson

     

    8.1.2.   applicationContext.xml

    Spring使用一个配置,SpringMVC使用另一个配置

    1个,组件扫描,<context:component-scan base-package="cn.itsource.ssm" />

    <import resource="classpath:applicationContext-mvc.xml" />

    8.1.3.   applicationContext-mvc.xml  4个

    mvc静态资源放行,mvc注解支持

    视图解析器,上传解析器

    <!-- 开启spring对springmvc的注解支持 -->

    <mvc:annotation-driven />

     

    <!-- 对于静态资源(图片,css,js)进行放行 -->

    <mvc:default-servlet-handler />

     

    <!-- 设置视图路径的前后缀,该配置可以让我们写视图路径的时候更简单。 -->

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

             <!--前缀: jsp在当前工程文件夹的路径 -->

             <property name="prefix" value="/WEB-INF/views/" />

             <!--后缀:扩展名 -->

             <property name="suffix" value=".jsp" />

    </bean>

     

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

             <!-- 设置上传文件的最大尺寸为1MB -->

             <property name="maxUploadSize">

                      <!-- spring el写法:5MB -->

                      <value>#{1024*1024*5}</value>

             </property>

    </bean>

    8.1.4.   web.xml

    1.post乱码过滤器

    2.springmvc核心控制器

    <!-- post提交中文乱码的过滤器 -->

    <filter>

             <filter-name>CharacterEncodingFilter</filter-name>

             <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

             <init-param>

                      <!-- 按照什么格式进行转码 -->

                      <param-name>encoding</param-name>

                      <param-value>UTF-8</param-value>

             </init-param>

    </filter>

     

    <filter-mapping>

             <filter-name>CharacterEncodingFilter</filter-name>

             <url-pattern>/*</url-pattern>

    </filter-mapping>

     

    <!-- 核心控制器 -->

    <servlet>

             <servlet-name>dispatcher</servlet-name>

             <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

             <init-param>

                      <param-name>contextConfigLocation</param-name>

                      <param-value>classpath:applicationContext.xml</param-value>

             </init-param>

             <load-on-startup>1</load-on-startup>

    </servlet>

    8.2.  集成MyBatis环境

    8.2.1.   加入MyBatis相关9个 jar包(mybatis-spring-1.2.0.jar)

    1. 核心包
    2. 依赖包(删除一个commons-logging-1.1.1.jar)
    3. 数据库连接包

     

    8.3.  Spring和MyBatis的集成方式

    8.3.1.   框架集成核心

    如果你的项目中,用到了Spring框架,那么其他框架主要就是和Spring集成!!

    8.3.2.   和Spring集成的顺序

    1. 把当前框架的核心类,交给Spring管理
    2. 如果框架有事务,那么事务也要统一交给Spring管理

    8.4.  Spring配置文件

    8.4.1.   jdbc配置文件&数据源dataSource

    <!-- Jdbc配置文件 -->

    <context:property-placeholder location="classpath:jdbc.properties" />

     

    <!-- 数据源dataSource -->

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

             <!-- 依赖注入连接池需要的属性 -->

             <!-- property name="是BasicDataSource的set方法,本质属性" -->

             <!-- property value="是jdbc.properties配置文件的key" -->

             <property name="driverClassName" value="${jdbc.driverClassName}" />

             <property name="url" value="${jdbc.url}" />

             <property name="username" value="${jdbc.username}" />

             <property name="password" value="${jdbc.password}" />

             <!--maxActive: 最大连接数量 -->

             <property name="maxActive" value="150" />

             <!--minIdle: 最小空闲连接 -->

             <property name="minIdle" value="5" />

             <!--maxIdle: 最大空闲连接 -->

             <property name="maxIdle" value="20" />

             <!--initialSize: 初始化连接 -->

             <property name="initialSize" value="30" />

             <!-- 连接被泄露时是否打印 -->

             <property name="logAbandoned" value="true" />

             <!--removeAbandoned: 是否自动回收超时连接 -->

             <property name="removeAbandoned" value="true" />

             <!--removeAbandonedTimeout: 超时时间(以秒数为单位) -->

             <property name="removeAbandonedTimeout" value="10" />

             <!--maxWait: 超时等待时间以毫秒为单位 1000等于60秒 -->

             <property name="maxWait" value="1000" />

             <!-- 在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位. -->

             <property name="timeBetweenEvictionRunsMillis" value="10000" />

             <!-- 在每次空闲连接回收器线程(如果有)运行时检查的连接数量 -->

             <property name="numTestsPerEvictionRun" value="10" />

             <!-- 1000 * 60 * 30 连接在池中保持空闲而不被空闲连接回收器线程 -->

             <property name="minEvictableIdleTimeMillis" value="10000" />

             <property name="validationQuery" value="SELECT NOW() FROM DUAL" />

    </bean>

    8.4.2.   SqlSessionFactoryBean

    SSJ集成时候需要entityManagerFactory

    SSM集成时候需要sqlSessionFactory

    resourcesMyBatis集成Spring文档资料mybatis-spring整合文档.exe

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

    8.4.3.   ssm注入顺序

    jdbc.properties->dataSource->sqlSessionFactory->mapper(dao)->service->controller(action)

    8.4.4.   获取sqlSessionFactory方案1

    <!-- Mybatis的核心类 -->

             <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

                      <property name="dataSource" ref="dataSource" />

                      <property name="configLocation" value="classpath:mybatis-config.xml"></property>

             </bean>

     

             <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">

                      <property name="sqlSessionFactory" ref="sqlSessionFactory" />

                      <property name="mapperInterface" value="cn.itsource.ssm.mapper.UserMapper" />

             </bean>

     

             <context:component-scan base-package="cn.itsource.ssm"/>

    8.4.5.   获取sqlSessionFactory方案2

    <!-- 配置sqlSessionFactory -->

             <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

                      <!-- 注入数据源 -->

                      <property name="dataSource" ref="dataSource" />

                      <!-- 配置mybatis (mapper)映射器路径 -->

                      <property name="mapperLocations" value="classpath:cn/itsource/ssm/mapper/*Mapper.xml" />

                      <!-- 配置mybatis 类型别名 -->

                      <property name="typeAliasesPackage">

                               <value>

                                        cn.itsource.ssm.domain

                                        Cn.itsource.ssm.query  可能有查询对象

                               </value>

                      </property>

             </bean>

    一劳永逸

             <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

                      <property name="basePackage" value="cn.itsource.ssm.mapper"></property>

             </bean>

     

     

     

    1. 课程总结

    9.1.  重点

    1. SSM集成,操作必须非常熟练
    2. 多对一嵌套结果,嵌套查询
    3. 一对多嵌套结果
    4. 映射器接口

    9.2.  难点

    1. 多对一嵌套结果:查询的有dept表的别名配置
    2. 映射文件里面使用${}的适用场景:order by
    3. 常见异常
    4. Caused by: java.io.NotSerializableException: cn.itsource.mybatis.day2._5_cache.User

    要使用二级缓存,要求domain必须实现序列化接口

    1. 课后练习
    2. 面试题
    3. 扩展知识或课外阅读推荐

    13.1.         扩展知识

    1. java.io.Serializable浅析

    http://www.cnblogs.com/gw811/archive/2012/10/10/2718331.html

    13.2.         课外阅读

  • 相关阅读:
    android 进程/线程管理(一)----消息机制的框架
    android的屏幕保持常亮
    android network develop(3)----Xml Parser
    android network develop(2)----network status check
    android network develop(1)----doing network background
    android 开发小记
    转 Android中shape中的属性大全
    转 Android学习 之 ColorStateList按钮文字变色
    《大话设计模式》c++实现 建造者模式
    《大话设计模式》c++实现 外观模式
  • 原文地址:https://www.cnblogs.com/Src-z/p/11218844.html
Copyright © 2020-2023  润新知