zoukankan      html  css  js  c++  java
  • 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.         课外阅读

  • 相关阅读:
    day 66 ORM django 简介
    day 65 HTTP协议 Web框架的原理 服务器程序和应用程序
    jQuery的事件绑定和解绑 事件委托 轮播实现 jQuery的ajax jQuery补充
    background 超链接导航栏案例 定位
    继承性和层叠性 权重 盒模型 padding(内边距) border(边框) margin 标准文档流 块级元素和行内元素
    属性选择器 伪类选择器 伪元素选择器 浮动
    css的导入方式 基础选择器 高级选择器
    03-body标签中相关标签
    Java使用内存映射实现大文件的上传
    正则表达式
  • 原文地址:https://www.cnblogs.com/Src-z/p/11218844.html
Copyright © 2011-2022 走看看