问题:spring 在整合mybatis的时候,我们是看不见sqlSessionFactory,和sqlsession(sqlsessionTemplate 就是sqlsession的具体实现)的,这是为什么?spring框架是怎么封装的,我们在配置文件中看到了这两个类:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:com/zhangshitong/mapping/*.xml"></property>
</bean>

<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.zhangshitong.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>

带着这些疑问,接着往下看:

前言

MyBatis相信很多人都会使用,但是当MyBatis整合到了Spring中,我们发现在Spring中使用更加方便了。例如获取Dao的实例,在Spring的我们只需要使用注入的方式就可以了使用Dao了,完全不需要调用SqlSession的getMapper方法去获取Dao的实例,更不需要我们去管理SqlSessionFactory,也不需要去创建SqlSession之类的了,对于插入操作也不需要我们commit。

既然那么方便,Spring到底为我们做了哪些工作呢,它如何将MyBatis整合到Spring中的呢,Spring在整合MyBatis时候做了哪些封装,以及做了哪些拓展,又是怎么实现这些封装以及拓展的,让我们来打开这一部分的源代码,一探究竟。

首先我们来先回顾下MyBatis的用法,以及Spring中MyBatis的使用方法。

MyBatis使用介绍

         单单MyBatis的使用比较简单,让我们来简单回顾一下他的使用方法。
 

建立PO

po用于对于数据库中数据的映射,使得开发者更加专注于Java类的使用,而不是对数据库的操作

  1. /**
  2. * @author: Fighter168
  3. */
  4. public class Person {
  5. private String id;
  6. private String name;
  7. //set get 方法、、、
  8. }

建立Mapper

mapper是数据库操作的映射文件,也就是我们常说的dao文件

  1. /**
  2. * @author: Fighter168
  3. */
  4. public interface PersonDao {
  5. public List<Person> query();
  6. public void save(Person p);
  7. public void delete(String id);
  8. }

建立配置文件

配置文件主要用于程序中可变性高的设置,Mybatis的配置文件主要存在于configuration.xml中,当然configuration.xml中省略了其他mybatis的配置,例如settings里面的配置等等,如果没有玩过MyBatis的同学可以去参考网上MyBatis的教程自己去了解了解。

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <!-- 对事务的管理和连接池的配置 -->
  7. <environments default="development">
  8. <environment id="development">
  9. <transactionManager type="JDBC" />
  10. <dataSource type="POOLED">
  11. <property name="driver" value="com.mysql.jdbc.Driver" />
  12. <property name="url" value="jdbc:mysql://localhost:3306/test" />
  13. <property name="username" value="root" />
  14. <property name="password" value="root" />
  15. </dataSource>
  16. </environment>
  17. </environments>
  18. <!-- mapping 文件路径配置 -->
  19. <mappers>
  20. <mapper resource="resource/PersonMapper.xml" />
  21. </mappers>
  22. </configuration>

建立映射文件

映射文件对应于Mybatis全局配置中的mappers配置属性,主要用于建立对应数据库操作接口的SQL映射。

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://www.mybatis.org/dtd/mybatis-3-mapper.dtd" >
  3. <mapper namespace="net.itaem.dao.PersonDao" >
  4. <resultMap id="resultMap" type="net.itaem.po.Person" >
  5. <result column="id" property="id" jdbcType="CHAR" />
  6. <result column="name" property="name" jdbcType="CHAR" />
  7. </resultMap>
  8. <!--添加-->
  9. <insert id="save"  parameterType="net.itaem.po.Person">
  10. insert into person(id,name) value(#{id,jdbcType=CHAR},#{name,jdbcType=CHAR})
  11. </insert>
  12. <!--查询-->
  13. <select id="query"  resultMap="resultMap">
  14. select * from person
  15. </select>
  16. <!--删除-->
  17. <delete id="delete" parameterType="java.lang.String">
  18. delete from person  where id=#{id,jdbcType=CHAR}
  19. </delete>
  20. </mapper>

建立测试类

           下面通过编写使用MyBatis实现查询的测试用例,比较简单,所以就不写太多注释了。
  1. /**
  2. * @author: Fighter168
  3. */
  4. public class Test {
  5. public static void main(String[] args) throws Exception {
  6. Reader reader=Resources.getResourceAsReader("resource/configuration.xml");
  7. SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);
  8. SqlSession session=sessionFactory.openSession();
  9. PersonDao personDao=session.getMapper(PersonDao.class);
  10. Person person=new Person("11","Fighter168");
  11. personDao.save(person);
  12. //这里一定要提交,不然数据无法插入
  13. session.commit();
  14. session.close();
  15. }
  16. }

Spring中使用MyBatis介绍

 
             Spring中使用MyBatis更加简单,为了对比一下,我们来先看看下面的小例子。
 

创建Spring配置文件

          里面主要配置的是数据源,sqlSessionFactory和Dao的信息。
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
  5. <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  6. <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  7. <property name="url" value="jdbc:mysql://localhost:3306/test"/>
  8. <property name="username" value="root"/>
  9. <property name="password" value="123abc"/>
  10. <!-- 连接池启动时候的初始连接数 -->
  11. <property name="initialSize" value="10"/>
  12. <!-- 最小空闲值 -->
  13. <property name="minIdle" value="5"/>
  14. <!-- 最大空闲值 -->
  15. <property name="maxIdle" value="20"/>
  16. <property name="maxWait" value="2000"/>
  17. <!-- 连接池最大值 -->
  18. <property name="maxActive" value="50"/>
  19. <property name="logAbandoned" value="true"/>
  20. <property name="removeAbandoned" value="true"/>
  21. <property name="removeAbandonedTimeout" value="180"/>
  22. </bean>
  23. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  24. <property name="configLocation" value="classpath:/resource/cfg.xml"/>
  25. <property name="dataSource" ref="dataSource"/>
  26. </bean>
  27. <bean id="personDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
  28. <property name="mapperInterface" value="net.itaem.dao.PersonDao"/>
  29. <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
  30. </bean>
  31. </beans>
            看到上面配置personDao,我们单独的使用一个Bean去创建它,也许我们会想到如果我们又几十甚至是几百个dao,那配置就可能很恐怖了,不过,Spring的作者也考虑到了这样的问题,针对这种情况,如果dao很多的情况,其实也是可以采取扫描dao的形式注入spring的,具体怎么实现,我们下面会继续介绍。

创建MyBatis配置文件

           mybatis的配置文件除了去掉environment标签,其他没啥区别。
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <!-- mapping 文件路径配置 -->
  7. <mappers>
  8. <mapper resource="resource/PersonMapper.xml" />
  9. </mappers>
  10. </configuration>

创建映射文件

            映射文件和之前的映射文件保持一致。
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://www.mybatis.org/dtd/mybatis-3-mapper.dtd" >
  3. <mapper namespace="net.itaem.dao.PersonDao" >
  4. <resultMap id="resultMap" type="net.itaem.po.Person" >
  5. <result column="id" property="id" jdbcType="CHAR" />
  6. <result column="name" property="name" jdbcType="CHAR" />
  7. </resultMap>
  8. <!--添加-->
  9. <insert id="save"  parameterType="net.itaem.po.Person">
  10. insert into person(id,name) value(#{id,jdbcType=CHAR},#{name,jdbcType=CHAR})
  11. </insert>
  12. <!--查询-->
  13. <select id="query"  resultMap="resultMap">
  14. select * from person
  15. </select>
  16. <!--删除-->
  17. <delete id="delete" parameterType="java.lang.String">
  18. delete from person  where id=#{id,jdbcType=CHAR}
  19. </delete>
  20. </mapper>

Spring使用MyBatis测试

         下面,让我先看看spring的测试用例中如何使用mybatis。
  1. /**
  2. * @author: Fighter168
  3. */
  4. public class SpringTest {
  5. public static void main(String[] args) {
  6. ApplicationContext context=new ClassPathXmlApplicationContext("resource/ApplicationContext.xml");
  7. PersonDao personDao=(PersonDao) context.getBean("personDao");
  8. Person person=new Person("12","Fighter168");
  9. personDao.save(person);
  10. }
  11. }
         通过上面的比较,我们发现,在Spring中使用MyBatis是相当方便的,不需要我们去管理sqlSessionFactory以及SqlSession的管理,更不需要我们去操作简单的事务。
 
 
          至于Spring到底做了上面工作,下面我们进入主题吧,一探究竟。
 
 

spring整合mybatis实现

 

SqlSessionFactoryBean的创建

            SqlSessionFactoryBean这个类实现了三个接口,一个是InitializingBean,另一个是FactoryBean,还有就是ApplicationListener接口。下面说明一下实现了这三个接口的,有什么作用
 
InitializingBean接口:实现了这个接口,那么当bean初始化的时候,spring就会调用该接口的实现类的afterPropertiesSet方法,去实现当spring初始化该Bean 的时候所需要的逻辑。
 
FactoryBean接口:实现了该接口的类,在调用getBean的时候会返回该工厂返回的实例对象,也就是再调一次getObject方法返回工厂的实例。
 
ApplicationListener接口:实现了该接口,如果注册了该监听的话,那么就可以了监听到Spring的一些事件,然后做相应的处理
 

SqlSessionFactoryBean的初始化

              SqlSessionFactory的初始化是在Spring初始化该Bean 的时候就会初始化,实现InitializingBean接口的目的就是为了这个,让我们看看SqlSessionFactoryBean中实现InitializingBean的afterPropertiesSet方法。

  1. /**
  2. * {@inheritDoc}
  3. */
  4. public void afterPropertiesSet() throws Exception {
  5. notNull(dataSource, "Property 'dataSource' is required");
  6. notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
  7. this.sqlSessionFactory = buildSqlSessionFactory();
  8. }
          从中我们可以看到,sqlSessionFactory的实例化便在这个方法里面实例化,buildSqlSessionFactory()方法会对我们的sqlSessionFactory做定制的初始化,初始化sqlSessionFactory有两种方式,一种是我们直接通过property直接注入到改实例中,另一种是通过解析xml的方式,就是我们在configuration.xml里面的配置,根据这些配置做了相应的初始化操作,里面也是一些标签的解析属性的获取,操作,和Spring的默认标签解析有点类似,这里就不再重复说明。
 

获取SqlSessionFactoryBean实例

           因为SqlSessionFactoryBean实现了FactoryBean接口,所以当我们通过getBean获取它的实例的时候实际是调用他的getObject方法,获取到的是sqlSessionFactory。
 
  1. /**
  2. * {@inheritDoc}
  3. */
  4. public SqlSessionFactory getObject() throws Exception {
  5. if (this.sqlSessionFactory == null) {
  6. afterPropertiesSet();
  7. }
  8. return this.sqlSessionFactory;
  9. }

所以我们在给dao注入sqlSessionFactory的时候,依赖填写SqlSessionFactoryBean 的实例就可以了。

 
 

MapperFactoryBean的创建

       在使用mybatis的时候,我们获取dao的方式一般是这样:
  1. SqlSession session=sessionFactory.openSession();
  2. PersonDao personDao=session.getMapper(PersonDao.class);

但在我们在spring的测试用例中使用mybatis的时候是这样使用的:

  1. PersonDao personDao=(PersonDao) context.getBean("personDao");

为什么spring可以这样做呢,答案就在MapperFactoryBean这里

 
让我先来看看这个类的类层次结构图:
 
MapperFactoryBean也实现了FactoryBean和InitializingBean接口,我们也从MapperFactoryBean的初始化开始吧,看看它如何初始化。
 

MapperFactoryBean初始化

MapperFactoryBean继承了SqlSessionDaoSupport,SqlSessionDaoSupport继承DaoSupport,DaoSupport实现了InitializingBean接口,让我们开看看它这接口的实现:
 
  1. public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
  2. // Let abstract subclasses check their configuration.
  3. checkDaoConfig();
  4. // Let concrete implementations initialize themselves.
  5. try {
  6. initDao();
  7. }
  8. catch (Exception ex) {
  9. throw new BeanInitializationException("Initialization of DAO failed", ex);
  10. }
  11. }
 

该方法主要包含两个功能,一个是调用checkDaoConfig()方法,一个是调用initDao方法。checkDaoConfig方法在DaoSupport是抽象方法,让我看看它在MapperFactoryBean的实现:

  1. /**
  2. * {@inheritDoc}
  3. */
  4. @Override
  5. protected void checkDaoConfig() {
  6. super.checkDaoConfig();
  7. notNull(this.mapperInterface, "Property 'mapperInterface' is required");
  8. Configuration configuration = getSqlSession().getConfiguration();
  9. if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
  10. try {
  11. configuration.addMapper(this.mapperInterface);
  12. } catch (Throwable t) {
  13. logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", t);
  14. throw new IllegalArgumentException(t);
  15. } finally {
  16. ErrorContext.instance().reset();
  17. }
  18. }
  19. }
 
             该方法主要是检查dao的配置,主要是检验sqlSessionFactory和mapperInterface属性不能为空,以及检测接口对于的映射文件是否存在,如果存在,那么就把它添加到configuration里面去,注册mapper。
 

获取MapperFactoryBean的实例

           MapperFactoryBean实现了FactoryBean接口,那么在调用getBean方法获取MapperFactoryBean实例的时候,实际上调用的就是getObject方法,让我们来看看getObject的实现:
  1. /**
  2. * {@inheritDoc}
  3. */
  4. public T getObject() throws Exception {
  5. return getSqlSession().getMapper(this.mapperInterface);
  6. }
        看到这里,我们会恍然大悟,原来在这里封装了getMapper操作,返回接口的实例,怪不得在Spring中使用MyBatis不用管理sqlSession了。
        所以对于上面的测试用例,Spring怎么封装了MyBatis,如何把sqlSessionFactory和sqlSession隐藏了起来,又怎么方便的获取dao接口实例,我们大概有了一个了解。
        
        那么让我在回到之前提到的那个问题,如果有成百上千个dao接口呢,那我们岂不是要配置添加成百上千个bean,当然不是这样,spring还为MyBatis添加了拓展的功能,可以通过扫描包目录的方式,添加dao,让我看看具体使用和实现。
 
 
 
 

MapperScannerConfigurer介绍

 
         如果我们的dao在一个包下面又好几十个,那么我可以可以通过扫描的方式添加dao,像下面一样使用
 
  1. <!-- 去掉该配置
  2. <bean id="personDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
  3. <property name="mapperInterface" value="net.itaem.dao.PersonDao"/>
  4. <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
  5. </bean>
  6. -->
  7. <!-- 如果 net.itaem.dao 包下面有很多dao需要注册,那么可以使用这种扫描的方式添加dao-->
  8. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  9. <property name="basePackage" value="net.itaem.dao"/>
  10. </bean>

看到上面的配置,我们会很好奇,在spring这样添加就可以扫描的方式添加dao配置,怎么做到的?让我打开类实现,具体看一下。

 
 
MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor接口,如果MapperScannerConfigurer实现了该接口,那么说明在application初始化的时候该接口会被调用,具体实现,让我先看看:
 
  1. /**
  2. * {@inheritDoc}
  3. *
  4. * @since 1.0.2
  5. */
  6. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
  7. if (this.processPropertyPlaceHolders) {
  8. processPropertyPlaceHolders();
  9. }
  10. ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
  11. scanner.setAddToConfig(this.addToConfig);
  12. scanner.setAnnotationClass(this.annotationClass);
  13. scanner.setMarkerInterface(this.markerInterface);
  14. scanner.setSqlSessionFactory(this.sqlSessionFactory);
  15. scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
  16. scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
  17. scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
  18. scanner.setResourceLoader(this.applicationContext);
  19. scanner.setBeanNameGenerator(this.nameGenerator);
  20. scanner.registerFilters();
  21. scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  22. }
 

这里我们重点关注三个主要的方法,分别是

processPropertyPlaceHolders(); 
scanner.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));

processPropertyPlaceHolders属性处理

执行属性的处理,简单的说,就是把xml中${XXX}中的XXX替换成属性文件中的相应的值
 
 

根据配置属性生成过滤器

scanner.registerFilters();方法会根据配置的属性生成对应的过滤器,然后这些过滤器在扫描的时候会起作用。
 
 
 

扫描java文件

scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
 
该方法主要做了以下操作:
1)扫描basePackage下面的java文件
2)解析扫描到的java文件
3)调用各个在上一步骤注册的过滤器,执行相应的方法。
4)为解析后的java注册bean,注册方式采用编码的动态注册实现。
5)构造MapperFactoryBean的属性,mapperInterface,sqlSessionFactory等等,填充到BeanDefinition里面去。
 
做完这些,MapperFactoryBean对象也就构造完成了,扫描方式添加dao的工作也完成了。
 
 

总结

                   其实了解了Spring整合MyBatis的流程,我们也就大体知道Spring整合一些框架所使用的扩展方法,不过大多是都是通过继承接口的方式,然后通过spring回调该接口的方式,实现我们自己想要的扩展逻辑,所以了解spring提供的一些扩展的接口以及抽象类是扩展的关键,就像InitializingBean,BeanDefinitionRegistryPostProcessor这些接口,知道了这些接口调用的方式,以及上面时候会调用,我们就可以知道,我们需要扩展的功能应该实现哪个接口,或者集成哪个抽象类。目前这些接口,官方没有整理出一份比较好的文档,不过在后续的博客中,我会把这些常用的拓展接口以及抽象类都提出来,介绍下,让大家熟悉下这些可以对spring进行扩展的接口以及抽象类。

spring 框架整合mybatis的源码分析的更多相关文章

  1. MyBatis框架的使用及源码分析(十一) StatementHandler

    我们回忆一下<MyBatis框架的使用及源码分析(十) CacheExecutor,SimpleExecutor,BatchExecutor ,ReuseExecutor> , 这4个Ex ...

  2. MyBatis框架的使用及源码分析(九) Executor

    从<MyBatis框架的使用及源码分析(八) MapperMethod>文中我们知道执行Mapper的每一个接口方法,最后调用的是MapperMethod.execute方法.而当执行Ma ...

  3. Spring框架之spring-web web源码完全解析

    Spring框架之spring-web web源码完全解析 spring-web是Spring webMVC的基础,由http.remoting.web三部分组成,核心为web模块.http模块封装了 ...

  4. Spring框架之spring-web http源码完全解析

    Spring框架之spring-web http源码完全解析 Spring-web是Spring webMVC的基础,由http.remoting.web三部分组成. http:封装了http协议中的 ...

  5. 【集合框架】JDK1.8源码分析之HashMap(一) 转载

    [集合框架]JDK1.8源码分析之HashMap(一)   一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Java8的HashMap对之前做了较大的优化 ...

  6. 【集合框架】JDK1.8源码分析之ArrayList详解(一)

    [集合框架]JDK1.8源码分析之ArrayList详解(一) 一. 从ArrayList字表面推测 ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,Lis ...

  7. Spring Boot 揭秘与实战 源码分析 - 工作原理剖析

    文章目录 1. EnableAutoConfiguration 帮助我们做了什么 2. 配置参数类 – FreeMarkerProperties 3. 自动配置类 – FreeMarkerAutoCo ...

  8. Spring Boot 揭秘与实战 源码分析 - 开箱即用,内藏玄机

    文章目录 1. 开箱即用,内藏玄机 2. 总结 3. 源代码 Spring Boot提供了很多”开箱即用“的依赖模块,那么,Spring Boot 如何巧妙的做到开箱即用,自动配置的呢? 开箱即用,内 ...

  9. Spring Environment(二)源码分析

    Spring Environment(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring Envi ...

随机推荐

  1. 搭建自己的代理服务 proxy nginx squid ss5 s(shadow)s(socks)

    标签: nginx / squid / 负载均衡 / ss 4090 1. nginx (forward) nginx自己熟悉,经常用来做负载均衡的反向代理, 这里搭建一个正向代理(forward) ...

  2. web前端学习笔记:文本属性

    今天的web前端笔记主要讲述文本属性,希望能帮助到正在学习web前端开发的初学者们,废话不多说了,一起来看看文本属性的相关内容吧. 文本属性 文本缩进 将Web页面上的一个段落第一行缩进,这是一种最常 ...

  3. python 正则表达式 group() groups()

    参考地址: http://www.cnblogs.com/kaituorensheng/archive/2012/08/20/2648209.html

  4. Tomcat的目录结构及部署应用程序

    下载好的二进制的Tomcat,解压会看到7个目录,如下: bin 目录:Tomcat的脚本存放目录,如启动.关闭脚本等.其中 **.bat用于windows平台,**.sh用于Linux平台 conf ...

  5. 移动端300ms延迟由来及解决方案

    1.300ms延迟由来 300 毫秒延迟的主要原因是解决双击缩放(double tap to zoom).双击缩放,顾名思义,即用手指在屏幕上快速点击两次,iOS 自带的 Safari 浏览器会将网页 ...

  6. Centos上安装phpmyadmin

    查看PHP有没有安装:php -v查看apache有没有安装:httpd -v如已经安装则想办法删除. 一.安装Apache(默认安装目录etc/httpd/) 1. 使用yum命令安装Apache ...

  7. 2017-2018-1 20155312《信息安全技术》实验二——Windows口令破解实验报告

    2017-2018-1 20155312<信息安全技术>实验二--Windows口令破解实验报告 实验目的 了解Windows口令破解原理 对信息安全有直观感性认识 能够运用工具实现口令破 ...

  8. kbmmw 5.05.00 发布

    新年前最后几天,kbmmw 发布了新版本,增加一大波功能.we are happy to announce v5.05.50 of our popular middleware for Delphi ...

  9. thinkphp5 数据库和模型

    1.Db和模型的存在只是ThinkPHP5.0架构设计中的职责和定位不同,Db负责的只是数据(表)访问,模型负责的是业务数据和业务逻辑.2.Db和模型最明显的一个区别就是Db查询返回的数据类型为数组( ...

  10. 基础知识之nginx重写规则

    nginx重写规则 nginx rewrite 正则表达式匹配 大小写匹配 ~ 为区分大小写匹配 ~* 为不区分大小写匹配 !~和!~*分别为区分大小写不匹配及不区分大小写不匹配 文件及目录匹配 -f ...