spring_mvc_mybatis傻瓜入门篇之spring与mybatis

  • 一.介绍

  • spring
  • 目前编程,一般我们都会在一个框架一下进行编程,而目前J2EE比较流行的框架,SPRING 当居其首。当然我们可以先撇开JAVA,撇开SPRING,一般进行编程都会运用到GOF中设计模式思想使得我们的代码程序可读可扩展解耦等等,那么在设计框架的时候,不管啥语言啥框架,他的中心思想就是屏蔽细节让我们用起来简单方便,实现这个目标有很多方式,那么作为GOD设计模式的延伸,一般的服务框架目前都已经运用IOC->AOP->SOA思想进行框架的设计实现!最基础的是 IOC,在此基础上实现AOP,SOA!关于其中的关系传送门在此!SPIRNG只是众多框架中的一种,但好用方便,所以用户众多!

  • SPRING_MVC

  • MVC是一种3层设计模式,web mvc 顾名思义就是web端的mvc,SPRING_MVC是对MVC的一种web实现!

  • Mybatis

  • mybaits封装了后台与数据库持久层的一个框架!

相互关系

spring作为核心可以自由的与各种持久层框架,web框架组合出不同的架构,如ssh(web框架struct,持久层框架hiberante)等!所以其他都可换,核心 spring 就不要换了,一个好的芯还是很重要的! 今天要入门的就是 spring + spring-mvc+mybatis

二.工具安装

工欲善其事必先利其器,spring 的开发都会有一个 sts的套件,其实 就是帮你安装好方便使用spring 相关插件的 eclipse !那就下载过来安装起来就好了!

三.创建项目

我们项目使用maven 管理,如果你还不知道maven ,那么找wikipedia 详细了解下,如果你只想知道在eclipse下的安装使用,那么这里你可以快速入门。 安装好之后之后,就可以建立maven工程,按说明next你就成功了:

image

通过pom.xml 配置文件引入各种需要的jar包具体看下面各个模块的需要引入!一般我们会引入日志,所以再配置下日志的配置文件如下(log4j.xml):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

	<!-- Appenders -->
	<appender name="console" class="org.apache.log4j.ConsoleAppender">
		<param name="Target" value="System.out" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%-5p: %c - %m%n" />
		</layout>
	</appender>
	
	<!-- Application Loggers -->
	<logger name="com.hundsun.smvc">
		<level value="info" />
	</logger>
	
	<!-- 3rdparty Loggers -->
	<logger name="org.springframework.core">
		<level value="info" />
	</logger>
	
	<logger name="org.springframework.beans">
		<level value="info" />
	</logger>
	
	<logger name="org.springframework.context">
		<level value="info" />
	</logger>

	<logger name="org.springframework.web">
		<level value="info" />
	</logger>

	<!-- Root Logger -->
	<root>
		<priority value="warn" />
		<appender-ref ref="console" />
	</root>
	
</log4j:configuration>

四 .spring

spring 框架只需要在 pom.xml上配置引入spring 的jar,如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.hundsun</groupId>
	<artifactId>smvc</artifactId>
	<name>smvc</name>
	<packaging>war</packaging>
	<version>1.0.0-BUILD-SNAPSHOT</version>
	<properties>
		<java-version>1.6</java-version>
		<org.springframework-version>4.2.0.RELEASE</org.springframework-version>
		<org.aspectj-version>1.6.10</org.aspectj-version>
		<org.slf4j-version>1.6.6</org.slf4j-version>
	</properties>
	<dependencies>
	<!-- Spring -->
	<!-- spring核心包 -->  
    <dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-core</artifactId>  
        <version>${org.springframework-version}</version>  
    </dependency>  
  
    <dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-web</artifactId>  
        <version>${org.springframework-version}</version>  
    </dependency>  
  
    <dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-oxm</artifactId>  
        <version>${org.springframework-version}</version>  
    </dependency>  
  
    <dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-tx</artifactId>  
        <version>${org.springframework-version}</version>  
    </dependency>  
  
    <dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-jdbc</artifactId>  
        <version>${org.springframework-version}</version>  
    </dependency>  
  
    <dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-webmvc</artifactId>  
        <version>${org.springframework-version}</version>  
    </dependency>  
  
    <dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-aop</artifactId>  
        <version>${org.springframework-version}</version>  
    </dependency>  
  
    <dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-context-support</artifactId>  
        <version>${org.springframework-version}</version>  
    </dependency>  
  
    <dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-test</artifactId>  
        <version>${org.springframework-version}</version>  
    </dependency>  
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
			<exclusions>
				<!-- Exclude Commons Logging in favor of SLF4j -->
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				 </exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>

	</dependencies>
</project>

五.在Spring中加入mybatis

先在pom.xml配置上mybatis 用到的引入包信息

<!-- jackson 包 -->
    <dependency>  
        <groupId>org.codehaus.jackson</groupId>  
        <artifactId>jackson-mapper-asl</artifactId>  
        <version>1.9.13</version>  
    </dependency>
		
		<!-- mybatis 包 -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.2.8</version>
		</dependency>

		<!--mybatis spring 插件 -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.2.2</version>
		</dependency>
		
		<!-- mysql连接 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.34</version>
		</dependency>
		
		<!-- dbcp的jar包,用来在applicationContext.xml中配置数据库 -->  
   		<dependency>  
           <groupId>commons-dbcp</groupId>  
           <artifactId>commons-dbcp</artifactId>  
           <version>1.2.2</version>  
   		</dependency>

配置jdbc 配置文件 (jdbc.properties)

url=jdbc:mysql://115.29.151.158:3306/mytrade?useUnicode=true&characterEncoding=utf8 
driver=com.mysql.jdbc.Driver
username=********
password=*******
#定义初始连接数  
initialSize=0 
#定义最大连接数  
maxActive=20  
#定义最大空闲  
maxIdle=20 
#定义最小空闲  
minIdle=1  
#定义最长等待时间  
maxWait=60000  
  • 配置spring 引入mybatis 的配置文件(spring-mybatis.xml)

  • <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"  
        xmlns:context="http://www.springframework.org/schema/context"  
        xmlns:mvc="http://www.springframework.org/schema/mvc"  
        xsi:schemaLocation="http://www.springframework.org/schema/beans    
      http://www.springframework.org/schema/beans/spring-beans-3.1.xsd    
      http://www.springframework.org/schema/context    
      http://www.springframework.org/schema/context/spring-context-3.1.xsd    
      http://www.springframework.org/schema/mvc    
      http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">  
      
        <!-- 自动扫描 -->  
        <context:component-scan base-package="com.test" />  
      
        <!-- 引入配置文件 -->  
        <bean id="propertyConfigurer"  
            class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
            <property name="location" value="classpath:jdbc.properties" />  
        </bean>  
      
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"  
            destroy-method="close">  
            <property name="driverClassName" value="${driver}" />  
            <property name="url" value="${url}" />  
            <property name="username" value="${username}" />  
            <property name="password" value="${password}" />  
            <!-- 初始化连接大小 -->  
            <property name="initialSize" value="${initialSize}"></property>  
            <!-- 连接池最大数量 -->  
            <property name="maxActive" value="${maxActive}"></property>  
            <!-- 连接池最大空闲 -->  
            <property name="maxIdle" value="${maxIdle}"></property>  
            <!-- 连接池最小空闲 -->  
            <property name="minIdle" value="${minIdle}"></property>  
            <!-- 获取连接最大等待时间 -->  
            <property name="maxWait" value="${maxWait}"></property>  
        </bean>  
      
        <!-- Spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->  
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
            <property name="dataSource" ref="dataSource" />  
            <!-- 自动扫描mapping.xml文件 -->  
            <property name="mapperLocations" value="classpath:com/test/mapping/*.xml"></property>  
        </bean>  
      
        <!-- DAO接口所在包名,Spring会自动查找其下的类 -->  
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
            <property name="basePackage" value="com.test.Dao" />  
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>  
        </bean>  
      
        <!-- 事务管理 -->  
        <bean id="transactionManager"  
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
            <property name="dataSource" ref="dataSource" />  
        </bean>  
      
    </beans>  
  • 将该配置文件添加到web.xml中
    	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
    	<context-param>
    		<param-name>contextConfigLocation</param-name>
    		<param-value>
    		/WEB-INF/spring/root-context.xml;
    		classpath:spring-mybatis.xml;
    		</param-value>
    到这里,我们需要的包都已经添加好了,然后我们就需要测试下我们的spring 通过mybatis与mysql 数据库是不是通的,当然我们得先把数据库,表都准备好了,这个就不说了!接下来你们可能觉得需要写代码,写一些model层出来通过mybatis与mysql进行联通了?不需要,我们只要借助一个mybatis中的神器 mybatis-generator 用来自动生成代码,当然你需要把mysql 的数据连接地址,需要生成的model 的表等一些信息配置起来!具体还是看前面链接里面的教程吧,就不重复说了:自动生成以下类:
    package com.test.Dao;
    
    import com.test.model.UserInfo;
    
    public interface UserInfoMapper {
        int deleteByPrimaryKey(Long positionInt);
    
        int insert(UserInfo record);
    
        int insertSelective(UserInfo record);
    
        UserInfo selectByPrimaryKey(Long positionInt);
    
        int updateByPrimaryKeySelective(UserInfo record);
    
        int updateByPrimaryKey(UserInfo record);
    }
                      然后把接口及服务层实现写出来,就写个简单的获取用户信息吧:

                      image

                      package com.test.service;
                      
                      import com.test.model.UserInfo;
                      
                      public interface IUserInfoService {
                      	public UserInfo getUserInfoById(long pos_int);
                      }
                      
                      package com.test.service.impl;
                      
                      import javax.annotation.Resource;  
                      import org.springframework.stereotype.Service;  
                      import com.test.model.UserInfo;  
                      import com.test.Dao.UserInfoMapper;  
                      import com.test.service.IUserInfoService; 
                      
                      @Service("userinfoService") 
                      public class UserInfoServiceImpl implements IUserInfoService {
                      	@Resource  
                          private UserInfoMapper userinfoDao;  
                      	
                      	@Override  
                          public UserInfo getUserInfoById(long pos_int) {  
                              return this.userinfoDao.selectByPrimaryKey(pos_int);  
                          }  
                      }
                      

                      然后写个 jtest:

                      package smvc;
                      
                      import javax.annotation.Resource;  
                      import org.apache.log4j.Logger;  
                      import org.junit.Test;  
                      import org.junit.runner.RunWith;  
                      import org.springframework.test.context.ContextConfiguration;  
                      import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
                      import com.alibaba.fastjson.JSON;  
                      import com.test.model.UserInfo;  
                      import com.test.service.IUserInfoService;  
                      
                      
                      @RunWith(SpringJUnit4ClassRunner.class)  
                      @ContextConfiguration(locations = { "classpath:spring-mybatis.xml" })  
                      public class TestMyBatis {
                      	private static Logger logger = Logger.getLogger(TestMyBatis.class);  
                      	
                      	 @Resource  
                      	 private IUserInfoService userinfoService = null;  
                      	 
                      	 @Test  
                      	    public void test1() {  
                      	        UserInfo userinfo = userinfoService.getUserInfoById((long) 1);  
                      	        logger.info(JSON.toJSONString(userinfo));  
                      	    }  
                      }

                      运行下,我们就可以愉快的得到数据了!

                      FTP服务器及账号访问设置

                      背景

                      最近做个项目与其他系统对接,接口数据他们非要以文件格式获取,好吧,

                      按照他们的需求要弄个FTP服务器,然后他们的系统还卖了好多地方(好有钱),

                      然后他们都要来取数据,有些数据公用的,有些数据还是私有的,好吧还要整好多

                      账号起来!

                      安装

                      FTP服务器是部署在linux系统上的,所以很自然就想到了用vsftpd,其他都不多说了,

                      直接把FTP服务安装起来再说了!安装还是直接使用yum(真神器!):

                      yum install vsftpd

                      就这么简单,然后啥都装好了!然后就启动服务就可以了:

                      service vsftpd start

                      配置

                      vsftpd.conf

                      vsftpd.conf 是vsftpd的配置文件,用来控制vsftpd的各项功能。默认状态下,它的位置

                      是/etc/vsftpd.conf或者在/etc/vsftpd/vsftpd.conf。里面的配置项的含义还是需要了解一番,

                      这里我就不多做介绍,你们直接传送门走起!

                      虚拟用户

                      看完上面的配置,那么我们就来进行本次重点内容虚拟用户的配置过程:

                      基本思路就是先创建一个用户,然后在这个用户下面挂多个虚拟的用户

                      进行!

                      mysql编译安装

                      以前的项目都用Oracle,新项目准备使用Mysql数据库,所以就先装个玩一下,把安装过程记录一下,当 是学习mysql 的开篇了!mysql是开源的,作为一只有那么点GEEK情结的超猿类,除了安装外,还是要编译一把才过瘾的!

                      编译

                      • 基础工具准备:

                        要编译,首先需要准备好编译的环境工具,此次我的linux环境还是CentOS6.5版本,通过以下脚本安装好最新的编译工具与库文件:

                      [root@iZ28gxqlqfsZ ~]# yum install gcc gcc-c++ ncurses-devel perl&lt;

                      同时我们需要安装cmake,我们使用当前最新的稳定版本V3.2,命令如下:

                      [root@iZ28gxqlqfsZ ~]# wget http://www.cmake.org/files/v3.2/cmake-3.2.0.tar.gz 
                      [root@iZ28gxqlqfsZ ~]# tar -xzvf cmake-3.2.0.tar.gz 
                      [root@iZ28gxqlqfsZ ~]# cd cmake-3.2.0
                      • 源码准备

                      正常进入mysql官网下载页面,找不到源码的下载按钮(听说是中国被墙),进入如下页面后选择一个国家的FTP资源去下载,我选择了鸟国的!

                      http://dev.mysql.com/downloads/mirrors.html
                      [root@iZ28gxqlqfsZ ~]# wgetftp:ftp://ftp.jaist.ac.jp/pub/mysql/Downloads/MySQL-5.5/mysql-5.5.44.tar.gz
                      [root@iZ28gxqlqfsZ ~]# tar -zxv -f mysql-5.5.44.tar.gz
                      • 用户环境准备:

                      数据库用户组与用户名

                      [root@iZ28gxqlqfsZ ~]# groupadd mysql
                      [root@iZ28gxqlqfsZ ~]# useradd -r -g mysql mysql

                      mysql安装目录

                      [root@iZ28gxqlqfsZ local]# mkdir <span style="color: #ff0000;">/usr/local/mysql</span>
                      [root@iZ28gxqlqfsZ local]# cd /usr/local/mysql
                      [root@iZ28gxqlqfsZ mysql]# chown -R mysql:mysql .
                      

                      mysql数据库文件目录

                      [root@iZ28gxqlqfsZ ~]# mkdir <span style="color: #ff0000;">/data/mysql</span>
                      [root@iZ28gxqlqfsZ ~]# cd /data/mysql
                      [root@iZ28gxqlqfsZ ~]# chown -R mysql:mysql .
                      

                      环境变形执行路径更改

                      vim /etc/profile 
                      #mysql path
                      PATH=/usr/local/mysql/bin:/usr/local/mysql/lib:$PATH
                      export PATH
                      
                      source /etc/profile

                      设置源码编译配置脚本:

                      [root@iZ28gxqlqfsZ mysql-5.5.44]# cmake \
                      > -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \
                      > -DDEFAULT_CHARSET=utf8 \
                      > -DDEFAULT_COLLATION=utf8_general_ci \
                      > -DWITH_INNOBASE_STORAGE_ENGINE=1 \
                      > -DWITH_ARCHIVE_STORAGE_ENGINE=1 \
                      > -DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
                      > -DMYSQL_DATADIR=/data/mysql \
                      > -DMYSQL_TCP_PORT=3306 \
                      > -DEXTRA_CHARSETS=all
                      • 编译mysql

                      删除CMakeCache.txt,后重新编译:

                      [root@iZ28gxqlqfsZ mysql-5.5.44]# rm CMakeCache.txt
                      [root@iZ28gxqlqfsZ mysql-5.5.44]# make
                      • 安装MYSQL:
                      [root@iZ28gxqlqfsZ mysql-5.5.44]# make install

                      到这一步mysql 数据库就已经编译安装好了!

                      初始化

                      • 初始化数据库
                      [root@iZ28gxqlqfsZ ~]# cd /usr/local/mysql
                      [root@iZ28gxqlqfsZ ~]# scripts/mysql_install_db --user=mysql --datadir=/data/mysql

                      配置文件修改

                      [root@iZ28gxqlqfsZ mysql]# cp /usr/local/mysql/support-files/my-medium.cnf /etc/my.cnf
                      [root@iZ28gxqlqfsZ mysql]# cp support-files/mysql.server /etc/init.d/mysqld
                      [root@iZ28gxqlqfsZ mysql]# cp /usr/local/mysql/support-files/my-medium.cnf  /usr/local/mysql/my.cnf
                      

                      修改启动参数:
                      my.cnf 配置的[mysqld]项新增两个目录配置

                      [root@iZ28gxqlqfsZ mysql]# vi /usr/local/mysql/my.cnf
                      
                      [mysqld]
                      ...
                      basedir = /usr/local/mysql
                      datadir = /data/mysql
                      
                      • 启动数据库

                      启动数据库并让数据库开机自动启动

                      [root@iZ28gxqlqfsZ ~]# /usr/local/mysql/scripts/mysql_install_db --user=mysql --datadir=/data/mysql

                      [root@iZ28gxqlqfsZ mysql]# chkconfig –level 35 mysqld on

                      检查mysql服务是否启动:查看3306端口是否由mysqld 进程正在监听,因为没有设置密码,直接打mysql 命令进入看是否能进入root用户

                      [root@iZ28gxqlqfsZ mysql]# netstat -tulnp | grep 3306
                      [root@iZ28gxqlqfsZ mysql]# mysql

                      到此,mysql 数据库已经编译安装完成!小伙伴可以愉快进去玩耍了!当然mysql 数据库跟Oracle 数据库的上层的使用基本差不多,只是有些细微的结构上的差别,下面就列出最基本的操作!

                       

                      mysql5.6安装

                      RPM方式安装MySQL5.6

                      a. 检查MySQL及相关RPM包,是否安装,如果有安装,则移除(rpm –e 名称)

                      1
                      [root@localhost ~]# rpm -qa | grep -i mysql

                      2
                      mysql-libs-5.1.66-2.el6_3.x86_64

                      3
                      [root@localhost ~]# yum -y remove mysql-libs*

                      b. 下载Linux对应的RPM包,如:CentOS6.4_64对应的RPM包,如下:

                      1
                      [root@localhost rpm]# ll

                      2
                      total 74364

                      3
                      -rw-r--r--. 1 root root 18442536 Dec 11 20:19 MySQL-client-5.6.15-1.el6.x86_64.rpm

                      4
                      -rw-r--r--. 1 root root  3340660 Dec 11 20:06 MySQL-devel-5.6.15-1.el6.x86_64.rpm

                      5
                      -rw-r--r--. 1 root root 54360600 Dec 11 20:03 MySQL-server-5.6.15-1.el6.x86_64.rpm

                      c. 安装MySQL

                      1
                      [root@localhost rpm]# rpm -ivh MySQL-server-5.6.15-1.el6.x86_64.rpm

                      2
                      [root@localhost rpm]# rpm -ivh MySQL-devel-5.6.15-1.el6.x86_64.rpm

                      3
                      [root@localhost rpm]# rpm -ivh MySQL-client-5.6.15-1.el6.x86_64.rpm

                      4
                      #修改配置文件位置

                      5
                      [root@localhost rpm]# cp /usr/share/mysql/my-default.cnf /etc/my.cnf

                      d. 初始化MySQL及设置密码

                      1
                      [root@localhost rpm]# /usr/bin/mysql_install_db

                      2
                      [root@localhost rpm]# service mysql start

                      3
                      [root@localhost rpm]# cat /root/.mysql_secret  #查看root账号密码

                      4
                      # The random password set for the root user at Wed Dec 11 23:32:50 2013 (local time): qKTaFZnl

                      5
                      [root@localhost ~]# mysql -uroot –pqKTaFZnl

                      6
                      mysql> SET PASSWORD = PASSWORD('123456');    #设置密码为123456

                      7
                      mysql> exit

                      8
                      [root@localhost ~]# mysql -uroot -p123456

                      e. 允许远程登陆

                      01
                      mysql> use mysql;

                      02
                      mysql> select host,user,password from user;

                      03
                      +-----------------------+------+-------------------------------------------+

                      04
                      | host                  | user | password                                  |

                      05
                      +-----------------------+------+-------------------------------------------+

                      06
                      | localhost             | root | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |

                      07
                      | localhost.localdomain | root | *1237E2CE819C427B0D8174456DD83C47480D37E8 |

                      08
                      | 127.0.0.1             | root | *1237E2CE819C427B0D8174456DD83C47480D37E8 |

                      09
                      | ::1                   | root | *1237E2CE819C427B0D8174456DD83C47480D37E8 |

                      10
                      +-----------------------+------+-------------------------------------------+

                      11

                      12
                      mysql> update user set password=password('123456') where user='root';

                      13
                      mysql> update user set host='%' where user='root' and host='localhost';

                      14
                      mysql> flush privileges;

                      15
                      mysql> exit

                      f. 设置开机自启动

                      1
                      [root@localhost ~]# chkconfig mysql on

                      2
                      [root@localhost ~]# chkconfig --list | grep mysql

                      3
                      mysql           0:off   1:off   2:on    3:on    4:on    5:on    6:off

                      g. MySQL的默认安装位置

                      1
                      /var/lib/mysql/               #数据库目录

                      2
                      /usr/share/mysql              #配置文件目录

                      3
                      /usr/bin                     #相关命令目录

                      4
                      /etc/init.d/mysql              #启动脚本

                      修改字符集和数据存储路径

                      配置/etc/my.cnf文件,修改数据存放路径、mysql.sock路径以及默认编码utf-8.

                      view plain copy

                      在CODE上查看代码片派生到我的代码片

                      1. [client]  
                      2. password        = 123456  
                      3. port            = 3306  
                      4. default-character-set=utf8
                      5. [mysqld]  
                      6. port            = 3306  
                      7. character_set_server=utf8
                      8. character_set_client=utf8
                      9. collation-server=utf8_general_ci
                      10. #(注意linux下mysql安装完后是默认:表名区分大小写,列名不区分大小写; 0:区分大小写,1:不区分大小写)  
                      11. lower_case_table_names=1
                      12. #(设置最大连接数,默认为 151,MySQL服务器允许的最大连接数16384; )  
                      13. max_connections=1000
                      14. [mysql]  
                      15. default-character-set = utf8

                      查看字符集

                      python安装

                      python2 python3 windows 下共存

                      关于Windows平台上Python2与Python3共存,使用过程中可能会遇到一些问题。关于网上其他的修改python.exe名字的做法都是不合适的。
                      下面是我从网上搜集过来的正确使用方法,可以完美使用,具体也可以参考官方说明3.4小节有详细说明

                      关于调用不同版本Python

                      如果同时安装了Python2和Python3,在安装Python3的时候勾选Install launcher for all users选项,这个选项默认会生成一个Python引导程序。同时最好也加入系统环境变量。

                      那么在使用的时候可以这样:

                      • 使用py -2 hello.py即可调用Python2执行hello.py。py -3 hello.py即可调用Python3来执行hello.py。

                      • 在hello.py文件的开头进行标记(可能叫法不对)在文件第一行写上#!python2,或者#!python3这样标记以后,在执行的时候只需要输入py hello.py,会自动调用相应的解释器来执行文件。
                        记得#!python2一定要放在第一行。

                      关于pip的使用
                      • 若需要安装Python2的库,执行py -2 -m pip install xxxx即可,xxxx是库的名字。
                        若需要安装Python3的库,执行py -3 -m pip install xxxx即可。

                      Better understanding Linux secondary dependencies solving with examples

                      除了man 资料外觉得是挺详细的资料,收藏!

                      http://www.kaizou.org/2015/01/linux-libraries/

                      08 Jan 2015 by David Corvoysier

                      A few months ago I stumbled upon a linking problem with secondary dependencies I couldn’t solved without overlinking the corresponding libraries.

                      I only realized today in a discussion with my friend Yann E. Morin that not only did I use the wrong solution for that particular problem, but that my understanding of the gcc linking process was not as good as I had imagined.

                      This blog post is to summarize what I have now understood.

                      There is also a small repository on github with the mentioned samples.

                      A few words about Linux libraries

                      This paragraph is only a brief summary of what is very well described in The Linux Documentation Project library howto.

                      Man pages for the linux linker and loader are also a good source of information.

                      There are three kind of libraries in Linux: static, shared and dynamically loaded (DL).

                      Dynamically loaded libraries are very specific to some use cases like plugins, and would deserve an article on their own. I will only focus here on static and shared libraries.

                      Static libraries

                      A static library is simply an archive of object files conventionally starting with thelib prefix and ending with the .a suffix.

                      Example:

                      libfoobar.a

                      Static libraries are created using the ar program:

                      $ ar rcs libfoobar.a foo.o bar.o

                      Linking a program with a static library is as simple as adding it to the link command either directly with its full path:

                      $ gcc -o app main.c /path/to/foobar/libfoobar.a

                      or indirectly using the -l/L options:

                      $ gcc -o app main.c -lfoobar -L/path/to/foobar

                      Shared libraries

                      A shared library is an ELF object loaded by programs when they start.

                      Shared libraries follow the same naming conventions as static libraries, but with the .sosuffix instead of .a.

                      Example:

                      libfoobar.so

                      Shared library objects need to be compiled with the -fPIC option that produces position-independent code, ie code that can be relocated in memory.

                      $ gcc -fPIC -c foo.c
                      $ gcc -fPIC -c bar.c

                      The gcc command to create a shared library is similar to the one used to create a program, with the addition of the -shared option.

                      $ gcc -shared -o libfoobar.so foo.o bar.o

                      Linking against a shared library is achieved using the exact same commands as linking against a static library:

                      $ gcc -o app main.c libfoobar.so

                      or

                      $ gcc -o app main.c -lfoobar -L/path/to/foobar

                      Shared libraries and undefined symbols

                      An ELF object maintains a table of all the symbols it uses, including symbols belonging to another ELF object that are marked as undefined.

                      At compilation time, the linker will try to resolve an undefined symbol by linking it either statically to code included in the overall output ELF object or dynamically to code provided by a shared library.

                      If an undefined symbol is found in a shared library, a DT_NEEDED entry is created for that library in the output ELF target.

                      The content of the DT_NEEDED field depends on the link command: – the full path to the library if the library was linked with an absolute path, – the library name otherwise (or the library soname if it was defined).

                      You can check the dependencies of an ELF object using the readelf command:

                      $ readelf -d main

                      or

                      $ readelf -d libbar.so

                      When producing an executable a symbol that remains undefined after the link will raise an error: all dependencies must therefore be available to the linker in order to produce the output binary.

                      For historic reason, this behavior is disabled when building a shared library: you need to specify the --no-undefined (or -z defs) flag explicitly if you want errors to be raised when an undefined symbol is not resolved.

                      $ gcc -Wl,--no-undefined -shared -o libbar.so -fPIC bar.c

                      or

                      $ gcc -Wl,--no-undefined -shared -o libbar.so -fPIC bar.c

                      Note that when producing a static library, which is just an archive of object files, no actual ‘linking’ operation is performed, and undefined symbols are kept unchanged.

                      Library versioning and compatibility

                      Several versions of the same library can coexist in the system.

                      By conventions, two versions of the same library will use the same library name with a different version suffix that is composed of three numbers:

                      • major revision,
                      • minor revision,
                      • build revision.

                      Example:

                      libfoobar.so.1.2.3

                      This is often referred as the library real name.

                      Also by convention, the library major version should be modified every time the library binary interface (ABI) is modified.

                      Following that convention, an executable compiled with a shared library version is theoretically able to link with another version of the same major revision.

                      This concept if so fundamental for expressing compatibility between programs and shared libraries that each shared library can be associated a soname, which is the library name followed by a period and the major revision:

                      Example:

                      libfoobar.so.1

                      The library soname is stored in the DT_SONAME field of the ELF shared object.

                      The soname has to be passed as a linker option to gcc.

                      $ gcc -shared -Wl,-soname,libfoobar.so.1 -o libfoobar.so foo.o bar.o

                      As mentioned before, whenever a library defines a soname, it is that soname that is stored in the DT_NEEDED field of ELF objects linked against that library.

                      Solving versioned libraries dependencies at build time

                      As mentioned before, libraries to be linked against can be specified using a shortened name and a path:

                      $ gcc -o app main.c -lfoobar -L/path/to/foobar

                      When installing a library, the installer program will typically create a symbolic link from the library real name to its linker name to allow the linker to find the actual library file.

                      Example:

                      /usr/lib/libfoobar.so -> libfoobar.so.1.5.3

                      The linker uses the following search paths to locate required shared libraries:

                      • directories specified by -rpath-link options (more on that later)
                      • directories specified by -rpath options (more on that later)
                      • directories specified by the environment variable LD_RUN_PATH
                      • directories specified by the environment variable LD_LIBRARY_PATH
                      • directories specified in DT_RUNPATH or DT_RPATH of a shared library are searched for shared libraries needed by it
                      • default directories, normally /lib and /usr/lib
                      • directories listed inthe /etc/ld.so.conf file

                      Solving versioned shared libraries dependencies at runtime

                      On GNU glibc-based systems, including all Linux systems, starting up an ELF binary executable automatically causes the program loader to be loaded and run.

                      On Linux systems, this loader is named /lib/ld-linux.so.X (where X is a version number). This loader, in turn, finds and loads recursively all other shared libraries listed in theDT_NEEDED fields of the ELF binary.

                      Please note that if a soname was specified for a library when the executable was compiled, the loader will look for the soname instead of the library real name. For that reason, installation tools automatically create symbolic names from the library soname to its real name.

                      Example:

                      /usr/lib/libfoobar.so.1 -> libfoobar.so.1.5.3

                      When looking fo a specific library, if the value described in the DT_NEEDED doesn’t contain a /, the loader will consecutively look in:

                      • directories specified at compilation time in the ELF object DT_RPATH (deprecated),
                      • directories specified using the environment variable LD_LIBRARY_PATH,
                      • directories specified at compile time in the ELF object DT_RUNPATH,
                      • from the cache file /etc/ld.so.cache, which contains a compiled list of candidate libraries previously found in the augmented library path (can be disabled at compilation time),
                      • in the default path /lib, and then /usr/lib (can be disabled at compilation time).

                      Proper handling of secondary dependencies

                      As mentioned in the introduction, my issue was related to secondary dependencies, ie shared libraries dependencies that are exported from one library to a target.

                      Let’s imagine for instance a program main that depends on a library libbar that itself depends on a shared library libfoo.

                      We will use either a static libbar.a or a shared libbar.so.

                      foo.c

                      int foo()
                      {
                          return 42;
                      }

                      bar.c

                      int foo();
                      
                      int bar()
                      {
                          return foo();
                      }

                      main.c

                      int bar();
                      
                      int main(int argc, char** argv)
                      {
                          return bar();
                      }

                      Creating the libfoo.so shared library

                      libfoo has no dependencies but the libc, so we can create it with the simplest command:

                      $ gcc -shared -o libfoo.so -fPIC foo.c

                      Creating the libbar.a static library

                      As said before, static libraries are just archives of object files, without any means to declare external dependencies.

                      In our case, there is therefore no explicit connection whatsoever between libbar.a and libfoo.so.

                      $ gcc -c bar.c
                      $ ar rcs libbar.a bar.o

                      Creating the libbar.so dynamic library

                      The proper way to create the libbar.so shared library it by explicitly specifying it depends on libfoo:

                      $ gcc -shared -o libbar2.so -fPIC bar.c -lfoo -L$(pwd)

                      This will create the library with a proper DT_NEEDED entry for libfoo.

                      $ readelf -d libbar.so
                      Dynamic section at offset 0xe08 contains 25 entries:
                        Tag        Type                         Name/Value
                       0x0000000000000001 (NEEDED)             Shared library: [libfoo.so]
                       0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
                      ...

                      However, since undefined symbols are not by default resolved when building a shared library, we can also create a “dumb” version without any DT_NEEDED entry:

                      $ gcc -shared -o libbar_dumb.so -fPIC bar.c

                      Note that it is very unlikely that someone actually chooses to create such an incomplete library on purpose, but it may happen that by misfortune you encounter one of these beasts in binary form and still need to link against it (yeah, sh… happens !).

                      Creating the main executable

                      Linking against the libbar.a static library

                      As mentioned before, when linking an executable, the linker must resolve all undefined symbols before producing the output binary.

                      Trying to link only with libbar.a produces an error, since it has an undefined symbol and the linker has no clue where to find it:

                      $ gcc -o app_s main.c libbar.a
                      libbar.a(bar.o): In function `bar':
                      bar.c:(.text+0xa): undefined reference to `foo'
                      collect2: error: ld returned 1 exit status

                      Adding libfoo.so to the link command solves the problem:

                      $ gcc -o app main.c libbar.a -L$(pwd) -lfoo

                      You can verify that the app binary now explicitly depends on libfoo:

                      $ readelf -d app
                      Dynamic section at offset 0xe18 contains 25 entries:
                        Tag        Type                         Name/Value
                       0x0000000000000001 (NEEDED)             Shared library: [libfoo.so]
                       0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
                      ...

                      At run-time, the dynamic linker will look for libfoo.so, so unless you have installed it in standard directories (/lib or /usr/lib) you need to tell it where it is:

                      LD_LIBRARY_PATH=$(pwd) ./app

                      To summarize, when linking an executable against a static library, you need to specify explicitly all dependencies towards shared libraries introduced by the static library on the link command.

                      Note however that expressing, discovering and adding implicit static libraries dependencies is typically a feature of your build system (autotools, cmake).

                      Linking against the libbar.so shared library

                      As specified in the linker documentation, when the linker encounters an input shared library it processes all its DT_NEEDED entries as secondary dependencies:

                      • if the linker output is a shared relocatable ELF object (ie a shared library), it will add all DT_NEEDED entries from the input library as new DT_NEEDED entries in the output,
                      • if the linker ouput is a non-shared, non-relocatable link (our case), it will automatically add the libraries listed in the DT_NEEDED of the input library on the link command line, producing an error if it can’t locate them.

                      So, let’s see what happens when dealing with our two shared libraries.

                      Linking against the “dumb” library

                      When trying to link an executable against the “dumb” version of libbar.so, the linker encounters undefined symbols in the library itself it cannot resolve since it lacks theDT_NEEDED entry related to libfoo:

                      $ gcc -o app main.c -L$(pwd) -lbar_dumb
                      libbar_dumb.so: undefined reference to `foo'
                      collect2: error: ld returned 1 exit status

                      Let’s see how we can solve this.

                      Adding explicitly the libfoo.so dependency

                      Just like we did when we linked against the static version, we can just add libfoo to the link command to solve the problem:

                      $ gcc -o app main.c -L$(pwd) -lbar_dumb -lfoo

                      It creates an explicit dependency in the app binary:

                      $ readelf -d app
                      Dynamic section at offset 0xe18 contains 25 entries:
                        Tag        Type                         Name/Value
                       0x0000000000000001 (NEEDED)             Shared library: [libbar_dumb.so]
                       0x0000000000000001 (NEEDED)             Shared library: [libfoo.so]
                       0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
                      ...

                      Again, at runtime you may need to tell the dynamic linker where libfoo.so is:

                      $ LD_LIBRARY_PATH=$(pwd) ./app

                      Note that having an explicit dependency to libfoo is not quite right, since our application doesn’t use directly any symbols from libfoo. What we’ve just done here is called overlinking, and it is BAD.

                      Let’s imagine for instance that in the future we decide to provide a newer version oflibbar that uses the same ABI, but based on a new version of libfoo with a different ABI: we should theoretically be able to use that new version of libbar without recompiling our application, but what would really happen here is that the dynamic linker would actually try to load the two versions of libfoo at the same time, leading to unpredictable results. We would therefore need to recompile our application even if it is still compatible with the newest libbar.

                      As a matter of fact, this actually happened in the past: a libfreetype update in the debian distro caused 583 packages to be recompiled, with only 178 of them actually using it.

                      Ignoring libfoo dependency

                      There is another option you can use when dealing with the “dumb” library: tell the linker to ignore its undefined symbols altogether:

                      $ gcc -o app main.c -L$(pwd) -lbar_dumb -Wl,--allow-shlib-undefined

                      This will produce a binary that doesn’t declare its hidden dependencies towards libfoo:

                      $ readelf -d app
                      Dynamic section at offset 0xe18 contains 25 entries:
                        Tag        Type                         Name/Value
                       0x0000000000000001 (NEEDED)             Shared library: [libbar_dumb.so]
                       0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
                      ...

                      This isn’t without consequences at runtime though, since the dynamic linker is now unable to resolve the executable dependencies:

                      $ ./app: symbol lookup error: ./libbar_dumb.so: undefined symbol: foo

                      Your only option is then to load libfoo explicitly (yes, this is getting uglier and uglier):

                      $ LD_PRELOAD=$(pwd)/libfoo.so LD_LIBRARY_PATH=$(pwd) ./app
                      Linking against the “correct” library
                      Doing it the right way

                      As mentioned before, when linking against the correct shared library, the linker encounters the libfoo.so DT_NEEDED entry, adds it to the link command and finds it at the path specified by -L, thus solving the undefined symbols … or at least that is what I expected:

                      $ gcc -o app main.c -L$(pwd) -lbar
                      /usr/bin/ld: warning: libfoo.so, needed by libbar.so, not found (try using -rpath or -rpath-link)
                      /home/diec7483/dev/linker-example/libbar.so: undefined reference to `foo'
                      collect2: error: ld returned 1 exit status

                      Why the error ? I thought I had done everything by the book !

                      Okay, let’s take a look at the ld man page again, looking at the -rpath-link option. This says:

                      When using ELF or SunOS, one shared library may require another. This happens when an “ld -shared” link includes a shared library as one of the input files. When the linker encounters such a dependency when doing a non-shared, non-relocatable link, it will automatically try to locate the required shared library and include it in the link, if it is not included explicitly. In such a case, the -rpath-link option specifies the first set of directories to search. The -rpath-link option may specify a sequence of directory names either by specifying a list of names separated by colons, or by appearing multiple times.

                      Ok, this is not crystal-clear, but what it actually means is that when specifying the path for a secondary dependency, you should not use -L but -rpath-link:

                      $ gcc -o app main.c -L$(pwd) -lbar -Wl,-rpath-link=$(pwd)

                      You can now verify that app depends only on libbar:

                      $ readelf -d app
                      Dynamic section at offset 0xe18 contains 25 entries:
                        Tag        Type                         Name/Value
                       0x0000000000000001 (NEEDED)             Shared library: [libbar.so]
                       0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
                      ...

                      And this is finally how things should be done.

                      You may also use -rpath instead of -rpath-link but in that case the specified path will be stored in the resulting executable, which is not suitable if you plan to relocate your binaries. Tools like cmake use the -rpath during the build phase (make), but remove the specified path from the executable during the installation phase(make install).

                      Conclusion

                      To summarize, when linking an executable against:

                      • a static library, you need to specify all dependencies towards other shared libraries this static library depends on explicitly on the link command.

                      • a shared library, you don’t need to specify dependencies towards other shared libraries this shared library depends on, but you may need to specify the path to these libraries on the link command using the -rpath/-rpath-link options.

                      Note however that expressing, discovering and adding implicit libraries dependencies is typically a feature of your build system (autotools, cmake), as demonstrated in my samples.

                      Memcache初探(二)分布式集群

                      要探讨memcache 的集群,那么就要先理解其特征,伪分布式。

                      这个要作两层理解:1.服务端数据可以进行分布式部署,但是需要依靠客户端的将数据根据算法进行分布式存储。

                      2.伪,上面的分布式需要依靠客户端实现,这是它第一个伪,还一个是 memcache 本身做不到可靠性,因为服务端相互之间不通信,不能同步数据,所以如果某一点挂了,就该缓存就失效了,并且如果客户端的算法是直接HASH的话,可能还会 影响后续缓存的命中。

                      magent

                      如果让客户端去实现分布式,我觉得这个会麻烦,同时而magent 这个代理就解决了memcashe上述的不足,客户端就只需要存入缓存,取缓存就够了,把一切什么麻烦的分布式,数据同步,可靠性,可用性全都交给magent 。所以一般我们需要集群方式使用memcache 的时候,一般都会增加magent 这个代理节点。当然客户端是少不了,既然提到了那也就讲一下,一般的使用memcache 的流程:

                      客户端(我们的应用服务) 通过memcache 提供的客户端(SDK)与memcache服务端连接,进行缓存数据的读写操作,如果需要集群,那么我们一般连接到magent,通过magent进行缓存数据读写,具体读写到哪个memcache节点,magent替我们做主,可靠性,可用性等也通过magent帮我们解决,其分布式使用.

                      magent wiki 给我们的简单示意图,这样memcached 就有主备,可以解决单点问题。

                      magent is a proxy server sitting between memcache clients(such as php programs) and memcached servers. magent have several advantages over direct connections
                      
                                      Client
                                        |
                                      Magent
                                        |
                          |--|--|-------------------|--|--|
                          |  |  |                   |  |  |
                        Normal Servers Farm      Backup Servers Farm
                      magent安装

                      1.mkdir magent 
                      2.cd magent/ 
                      3.wget http://memagent.googlecode.com/files/magent-0.5.tar.gz
                      4.tar zxvf magent-0.5.tar.gz 
                      5./sbin/ldconfig 
                      6.sed -i “s#LIBS = -levent#LIBS = -levent -lm#g” Makefile 
                      7.make 
                      8.cp magent /usr/bin/magent 
                      9.cd ../

                      一步步来,当然安装还是要有root 权限,有啥问题就google 吧,貌似ketama.h

                      的头文件需要添加以下预定义宏

                      #ifndef SSIZE_MAX  
                      #define SSIZE_MAX      32767  
                      #endif

                      算上前面一篇这样子我们就安装好了magent,memcached。我们就来个最简单的集群吧:

                      1.启动memcashe与magent

                      memcached -m 1 -u weekcashe -d -l 127.0.0.1 -p 11222
                      
                      memcached -m 1 -u weekcashe -d -l 127.0.0.1 -p 11223
                      
                      
                      memcached -m 1 -u weekcashe -d -l 127.0.0.1 -p 11224
                      magent -u weekcashe -n 51200 -l 127.0.0.1 -p 10000 -s 127.0.0.1:11222 -s 127.0.0.1:11223 -b 127.0.0.1:11224
                      
                      magent -u weekcashe -n 51200 -l 127.0.0.1 -p 11000 -s 127.0.0.1:11222 -s 127.0.0.1:11223 -b 127.0.0.1:11224
                      

                      2.可用性测试

                      [weekcashe@iZ28gxqlqfsZ ~]$ telnet 127.0.0.1 10000 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. set key 0 0 8 888888 STORED quit Connection closed by foreign host. [weekcashe@iZ28gxqlqfsZ ~]$ telnet 127.0.0.1 11222 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. get key VALUE key 0 8 888888 END quit Connection closed by foreign host. [weekcashe@iZ28gxqlqfsZ ~]$ telnet 127.0.0.1 11223 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. get key END quit Connection closed by foreign host. [weekcashe@iZ28gxqlqfsZ ~]$ telnet 127.0.0.1 11224 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. get key VALUE key 0 8 888888 END quit Connection closed by foreign host. [weekcashe@iZ28gxqlqfsZ ~]$ telnet 127.0.0.1 11000 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. get key VALUE key 0 8 888888 END quit Connection closed by foreign host.

                      3.可靠性测试

                      [weekcashe@iZ28gxqlqfsZ ~]$ ps x
                        PID TTY      STAT   TIME COMMAND
                       1600 ?        Ssl    0:00 memcached -d -u weekcashe -p 11222 -c 256 -P /tmp/memcached.pid
                       1615 ?        Ssl    0:00 memcached -d -u weekcashe -p 11223 -c 256 -P /tmp/memcached.pid
                       1630 ?        Ssl    0:00 memcached -d -u weekcashe -p 11224 -c 256 -P /tmp/memcached.pid
                       1658 ?        Ss     0:00 magent -u weekcashe -n 51200 -l 127.0.0.1 -p 10000 -s 127.0.0.1:11222 -s 127.0.0.1:11223 -b 127.0.0.1:11224
                       1660 ?        Ss     0:00 magent -u weekcashe -n 51200 -l 127.0.0.1 -p 11000 -s 127.0.0.1:11222 -s 127.0.0.1:11223 -b 127.0.0.1:11224
                       1726 pts/2    R+     0:00 ps x
                      [weekcashe@iZ28gxqlqfsZ ~]$ kill 1600
                      [weekcashe@iZ28gxqlqfsZ ~]$ telnet 127.0.0.1 11222
                      Trying 127.0.0.1...
                      telnet: connect to address 127.0.0.1: Connection refused
                      
                      [weekcashe@iZ28gxqlqfsZ ~]$ telnet 127.0.0.1 10000
                      Trying 127.0.0.1...
                      Connected to 127.0.0.1.
                      Escape character is '^]'.
                      get key
                      VALUE key 0 8
                      
                      888888
                      END
                      quit
                      Connection closed by foreign host.
                      
                      [weekcashe@iZ28gxqlqfsZ ~]$ memcached -d -u weekcashe -p 11222 -c 256 -P /tmp/memcached.pid
                      [weekcashe@iZ28gxqlqfsZ ~]$ ps x
                        PID TTY      STAT   TIME COMMAND
                       1365 ?        S      0:00 sshd: weekcashe@pts/0
                       1366 pts/0    Ss     0:00 -bash
                       1487 ?        S      0:00 sshd: weekcashe@pts/2
                       1488 pts/2    Ss     0:00 -bash
                       1615 ?        Ssl    0:00 memcached -d -u weekcashe -p 11223 -c 256 -P /tmp/memcached.pid
                       1630 ?        Ssl    0:00 memcached -d -u weekcashe -p 11224 -c 256 -P /tmp/memcached.pid
                       1658 ?        Ss     0:00 magent -u weekcashe -n 51200 -l 127.0.0.1 -p 10000 -s 127.0.0.1:11222 -s 127.0.0.1:11223 -b 127.0.0.1:11224
                       1660 ?        Ss     0:00 magent -u weekcashe -n 51200 -l 127.0.0.1 -p 11000 -s 127.0.0.1:11222 -s 127.0.0.1:11223 -b 127.0.0.1:11224
                       1730 ?        Ssl    0:00 memcached -d -u weekcashe -p 11222 -c 256 -P /tmp/memcached.pid
                       1744 pts/2    R+     0:00 ps x
                      
                      [weekcashe@iZ28gxqlqfsZ ~]$ telnet 127.0.0.1 10000
                      Trying 127.0.0.1...
                      Connected to 127.0.0.1.
                      Escape character is '^]'.
                      get key
                      END

                      我可以看出,当11222挂掉的时候,magent依然可以从备机器中取到缓存数据。

                      但是当11222被重新启动后,因为数据丢失,但是magent 未更新hash 对,依然命中到 11222去取数据,导致取不到数据。备机数据失效。这个问题留待解决。

                      你好通过 magent 端口 10000 写入的数据存储在了 memcashe 端口11222及备份memcashe 11224上,并且可以在 magent 11000 上获取到。并且设置获取数据magent 与直接在memcashe 端口上的接口是一致的。

                      OK,现在后台模拟集群的memcashe环境已经搭建完毕,通过magent 也已经解决了伪分布式带来的一些麻烦,那么接下就可以直接开始使用用客户端接口进行实际编码工作了。

                      xmemcached 客户端SDK使用了 NIO 机制,可以方便实现大并发。如果一般玩票性质就直接上 memcached client for java ,虽然其通信方式是传统的阻塞IO模型但足够稳定,不是超大型的已经够用。

                      Memcache初探-安装

                      作为一种NOSQL内存式数据库,一般用作数据缓存,目前我们公司用来作为关系型数据库的内存的缓存库,当然做过一些封装与更改,难免在使用上都与原库有所差异,所以就安装下原库试下最原始的用法

                      既然提了就说一下其特性:伪分布式

                       

                      服务端安装

                      安装
                      yum -y install memcached
                      授权

                      如果你的安装用户没有root授权,那么刚才的安装会提示错误,需要以下命令授权当前用户,安装不会出错。

                      su
                      帮助

                      使用如下蓝色命令可以查看memcached的使用帮助,参数的作用并附带校验安装是否成功。

                      # memcached -h
                      memcached 1.4.4
                      -p <num>      TCP port number to listen on (default: 11211)
                      -U <num>      UDP port number to listen on (default: 11211, 0 is off)
                      -s <file>     UNIX socket path to listen on (disables network support)
                      -a <mask>     access mask for UNIX socket, in octal (default: 0700)
                      -l <ip_addr>  interface to listen on (default: INADDR_ANY, all addresses)
                      -d            run as a daemon
                      -r            maximize core file limit
                      -u <username> assume identity of <username> (only when run as root)
                      -m <num>      max memory to use for items in megabytes (default: 64 MB)
                      -M            return error on memory exhausted (rather than removing items)
                      -c <num>      max simultaneous connections (default: 1024)
                      -k            lock down all paged memory.  Note that there is a
                                    limit on how much memory you may lock.  Trying to
                                    allocate more than that would fail, so be sure you
                                    set the limit correctly for the user you started
                                    the daemon with (not for -u <username> user;
                                    under sh this is done with 'ulimit -S -l NUM_KB').
                      -v            verbose (print errors/warnings while in event loop)
                      -vv           very verbose (also print client commands/reponses)
                      -vvv          extremely verbose (also print internal state transitions)
                      -h            print this help and exit
                      -i            print memcached and libevent license
                      -P <file>     save PID in <file>, only used with -d option
                      -f <factor>   chunk size growth factor (default: 1.25)
                      -n <bytes>    minimum space allocated for key+value+flags (default: 48)
                      -L            Try to use large memory pages (if available). Increasing
                                    the memory page size could reduce the number of TLB misses
                                    and improve the performance. In order to get large pages
                                    from the OS, memcached will allocate the total item-cache
                                    in one large chunk.
                      -D <char>     Use <char> as the delimiter between key prefixes and IDs.
                                    This is used for per-prefix stats reporting. The default is
                                    ":" (colon). If this option is specified, stats collection
                                    is turned on automatically; if not, then it may be turned on
                                    by sending the "stats detail on" command to the server.
                      -t <num>      number of threads to use (default: 4)
                      -R            Maximum number of requests per event, limits the number of
                                    requests process for a given connection to prevent 
                                    starvation (default: 20)
                      -C            Disable use of CAS
                      -b            Set the backlog queue limit (default: 1024)
                      -B            Binding protocol - one of ascii, binary, or auto (default)
                      -I            Override the size of each slab page. Adjusts max item size
                                    (default: 1mb, min: 1k, max: 128m)
                      启动

                      根据上面的帮助信息结合自己的实际情况启动memcashed服务,-d表示守护进程方式启动。

                      # memcached -d -u username -c 256 -P /tmp/memcached.pid

                      默认方式启动

                      /etc/init.d/memcached start
                      开机启动
                      chkconfig --level 2345 memcached on
                      检测

                      启动完成后,检测下memcached 服务是否已经OK,由于我们启动使用了默认端口,查看默认配置可以到如下路劲文件去看

                      vi /etc/sysconfig/memcached
                      
                      PORT="11211"
                      USER="memcached"
                      MAXCONN="1024"
                      CACHESIZE="64"
                      OPTIONS=""
                      

                      我们看到默认端口是11211,那么我们使用memcashe-tool工具去查看下当前服务状态:

                      memcached-tool 127.0.0.1:11211 stats
                      #127.0.0.1:11211   Field       Value
                               accepting_conns           1
                                     auth_cmds           0
                                   auth_errors           0
                                         bytes           0
                                    bytes_read           7
                                 bytes_written           0
                                    cas_badval           0
                                      cas_hits           0
                                    cas_misses           0
                                     cmd_flush           0
                                       cmd_get           0
                                       cmd_set           0
                                   conn_yields           0
                         connection_structures           6
                              curr_connections           5
                                    curr_items           0
                                     decr_hits           0
                                   decr_misses           0
                                   delete_hits           0
                                 delete_misses           0
                                     evictions           0
                                      get_hits           0
                                    get_misses           0
                                     incr_hits           0
                                   incr_misses           0
                                limit_maxbytes    67108864
                           listen_disabled_num           0
                                           pid        6322
                                  pointer_size          64
                                 rusage_system    0.000000
                                   rusage_user    0.000999
                                       threads           4
                                          time  1453353845
                             total_connections           6
                                   total_items           0
                                        uptime          19
                                       version       1.4.4
                      测试示例
                      telnet 127.0.0.1 11211
                      Trying 127.0.0.1...
                      Connected to 127.0.0.1.
                      Escape character is '^]'.
                      set foo 0 0 3
                      bar
                      STORED
                      get foo
                      VALUE foo 0 3
                      bar
                      END
                      使用示例
                      Cache Results
                      
                      function get_foo(foo_id)
                          foo = memcached_get("foo:" . foo_id)
                          return foo if defined foo
                      
                          foo = fetch_foo_from_database(foo_id)
                          memcached_set("foo:" . foo_id, foo)
                          return foo
                      end
                      关闭
                      kill `cat /tmp/memcached.pid`
                      /etc/init.d/memcached stop

                       

                      安装其实还涉及到一个分布式集群安装,因为还涉及到具体应用就放下一章节讲吧!

                      java学习路线(转)

                      比较全,根据自己情况挑着学吧http://blog.csdn.net/pplcheer/article/details/12276999

                      • 熟悉一种文本编辑器,比如Vim, Emacs, Notepad++, TextMate等。知道哪些是开源的,哪些是闭源的,哪些要收费。养成不用盗版软件的习惯。

                      • 安装JDK(建议用你的Linux发行版自带的软件包管理器安装openjdk,过程中可能需要读发行版特定的文档)

                      • 写一个Java的Helloworld程序,并用命令行工具javac编译,再用java命令运行这个程序。过程中熟悉源代码、字节码、虚拟机这些东西,以及Java的包(package)对.class文件所在的路径的影响。如果这两个命令行工具使用熟练了,可以开始选一个喜欢的集成开发环境,比如Eclipse。当然,养成不用盗版软件的习惯。熟悉一下如何建立“工程”,以及快捷键的使用。

                      • 学习Java的面向过程编程,包括基本数据结构、表达式、语句、控制流、函数调用。

                      • 学习Java的面向对象编程,包括类、引用类型和值类型的区别、成员、方法、访问控制、继承、多态、接口、接口实现。顺便学习一下面向对象的基本思想,即对象、消息、封装、继承、多态等,这些通用的内容不是Java特有的。这时候应该已经涉及了Java的垃圾回收。要留意即使有垃圾回收的情况下也会发生的内存泄露(如自己设计数组容器,元素是引用,逻辑上删除了元素,但并没有清成null)。注意垃圾回收只能回收内存中的对象,除了内存以外,其它资源不能依靠垃圾回收来关闭。比如,文件、管道、Socket、数据库连接等,垃圾回收是不会帮你关闭的。

                      • 学习Java的异常处理,但更重要的是学习什么时候用特殊返回值而不使用异常,什么时候应该抛出异常而不处理异常,知道什么是pokemon catch及其危害,了解为什么Java的checked exception是一个糟糕的特性。如果愿意,同时学习一下Java1.7的try-with-resource语句和AutoCloseable接口。

                      • 熟悉Java常用的数据结构,如基本的数组类型,以及泛型容器(java.util.*),尤其是java.util.List接口和java.util.ArrayList实现;以及java.util.Map接口和java.util.HashMap实现。(java1.5以前的没有泛型参数的就不用碰了)同时留意一下基本类型int, double等和装箱类型Integer和Double的区别,以及它们是如何自动转换的。

                      • 熟悉Java标准库里的各种工具,包括日期时间、字符串格式化、IO等。**知道文件要自己在finally子句中close(),或者用Java1.7的try-with-resource,不要妄想垃圾回收器会帮你关掉文件。

                      • 学习一下Java的命名习惯,以及JavaBeans的常规,知道为什么getter/setter比直接操作成员变量好。按这种方式给Java的变量、方法命名。同时看看你的IDE能不能自动帮你生成getter和setter。

                      • 使用一个第三方的库(比如Apache Commons Lang通用工具库),让你的程序依赖于它的二进制jar包(而不是直接拷贝源代码),用命令行编译、运行(注意classpath等);也熟悉一下如何用你的集成开发环境添加第三方依赖。感受一下手动管理依赖关系的麻烦。

                      • 学习Maven的使用,试着让Maven帮你解决依赖关系,再试着让Maven帮你创建一个Eclipse工程。再试试用Maven打包发布。

                      • 学习软件测试,以及JUnit的使用,以及怎么在IDE中使用JUnit。有空看一下coverage工具。

                      • 读读四人帮写的《设计模式》(这本书是用C++和Smalltalk语言为例子的,但仍然适合Java)。具体的是这本书,http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612图书馆应该能还借到英文原版,因为我借到过。


                      接下来就看具体要做哪方面的应用了,看需求。比如(下面的没有顺序)

                      1. 关于语言

                        • 如果学Java学得不舒服了,学Python。
                        • 如果对面向对象编程的概念有点不习惯,学Smalltalk。(Ruby也行,但不如Smalltalk经典。Ruby的文档是一大硬伤。)
                        • 如果嫌Java太啰嗦,学Python
                        • 如果嫌Java太啰嗦,又想用JVM,自己又有精力,学Scala
                        • 如果对对象之间的关系有点晕,学一学UML,以及它的一些图,可以对程序和运行进行直观的建模。你的IDE也许有插件可以生成UML图。但是不要太沉迷于这些方法论。
                      2. 调试和辅助工具

                        学习一下你的集成开发环境提供的调试工具,加一些断点试试。

                        • 试试用jconsole或者VisualVM监控另一个jvm的状态。
                        • 用profiling工具寻找程序中慢的地方。Eclipse有profiling工具。VisualVM也有这样的功能。(如果不介意使用闭源软件的话,也试试JProfiler和YourKit)
                        • 有的JVM允许在运行时更新代码。Eclipse可以和某些JVM集成。这样你可以频繁修改代码而不用频繁重启JVM。对于某些“重型”工程很有用。(如果不介意使用闭源软件的话,也试试jRebel)
                      3. 多线程

                        学习Java的多线程编程以及lock、condition的用法(包括传统Java的synchronized语句以及新加的java.util.concurrent.*),学习一下如何让线程停下来,以及为什么要频繁确认isInterrupted()而不要用Thread.stop()。了解一下多核处理器、缓存、内存的关系,以及为什么多线程编程这么难。

                        • 如果还舒服,学习一下Runnable的用法,以及自带的Executer等基本多线程工具。
                        • 应该已经留意到java.util里面的很多容器不是线程安全的,但是java.util.Collections可以帮你创建一些安全的版本。另外关注一下java.util.concurrent里面有ConcurrentMap等容器可供使用。
                        • 如果有空的话,看看memory model(内存一致性模型)和无锁同步(见java memory model和java.util.concurrent.atomic)。
                        • 如果还有空,再了解一下除了“共享内存多线程编程”以外有没有别的模型(多进程multi-processing、消息传递message passing等)。
                      4. 反射、元编程

                        • 学习Java的反射机制,以及Annotation的用法。
                        • 如果还舒服,试试java.lang.reflect.Proxy的用法。
                        • 如果仍然还舒服,玩一玩CGLib(一个第三方的库)。
                      5. 网络编程

                        学习一下IP,TCP协议(计算机专业的应该学过,复习一下),学习Socket编程(注意垃圾回收器不会帮你关掉Socket)。

                        • 如果不是很关心HTTP,看看java.nio,学习单线程轮询式IO复用(Selector)。
                          1. 如果有点不明白nio的意图的话,了解一下c10k问题。 http://www.kegel.com/c10k.html
                          2. 如果身体没有异样的话,大概了解一下操作系统(包括C语言)提供的select, poll, epoll, kqueue等接口。
                          3. 如果身体仍然没有异样的话,试着用java.nio写一个文件服务器。
                          4. 如果还有精力的话,上网扒一扒有没有其他的通信库,如netty等。
                        • 如果关心Web还有HTTP,就学习一下HTTP协议,以及用Java进行HTTP的客户端编程。
                          1. 如果还舒服,学学HTML,写写HTML的静态网页(不需要Java)
                          2. 如果还舒服,用Java写一个基于DOM、XPath或者CSS Selector的网页解析器(爬网页)。
                          3. 如果还舒服,学学Java的Servlet接口(先别学jsp)进行Web服务器端编程。学学标准的Servlet容器怎么用,包括web.xml的用法以及listener、filter等概念。以及某个Servlet容器(如Jetty或者Tomcat)的具体用法。
                          4. 如果仍然还舒服,试着学一种模板语言(如haml, velocity, freemarker,【还有其他更好的框架吗?我不知道】, String.format,如果真的想学JSP的话JSP倒是也行,但不推荐)。
                          5. 如果仍然觉得舒服,学学Spring框架中的Web框架,或者Struts,看你的口味。
                          6. 如果还舒服,看看Spring Bean Container以及里面各种乱七八糟的工具。
                          7. 如果还舒服,或者有需求,了解一下什么是RESTful Web Service,复习一下HTTP,找找适合的Java工具。
                          8. 你可能会觉得Jackson是一个解析JSON用的好用的东西。
                      6. 数据库

                        学习一下关系数据库(计算机专业的应该学过,复习一下),包括SQL。选一个数据库管理系统熟悉一下(比如MariaDB,或者(如果你不讨厌Oracle的话)用被Oracle收购了的MySQL。先脱离Java单独学学)。然后看它们的官方文档教你怎么用Java连接这种数据库。这中间会涉及到JDBC接口。同时一定要知道SQL注入安全漏洞,以及掌握如何用PreparedStatement防止注入!!。建议看 http://bobby-tables.com/

                        • 可能中间会涉及“事务”问题,让你不知不觉地开始去了解java transaction api(JTA)。
                        • 如果还舒服,学一学对象关系转换(如Hibernate)。
                        • 也可以学学非关系数据库,以及如何用Java访问它们。
                      7. 日志记录

                        学习一下slf4j和logback的用法。

                        • 如果有精力的话,大概了解一下世界上有多少种Java日志框架,以及slf4j是怎么桥接这些框架的。
                      8. 构建(build)系统

                        学习一下Ant的用法。

                        • 如果还舒服的话,学习一下用Ivy从Maven的仓库里下载软件包,解决依赖关系。
                      9. 版本控制

                        学习一种分布式版本控制器(如Git、Mercurial、Bzr、Darcs等,推荐Git)的基本用法,以及如何用它管理Java工程。希望你已经开始使用Maven了,并且知道为什么把IDE生成的工程文件(如eclipse的.project,.classpath和.metadata)放入版本控制器不好。然后了解一下如何在IDE中使用版本控制(Eclipse自带Git插件)。

                        • 如果感觉很舒服的话,为你们实验室搭建一个Linux+SSH+Git服务器,装个GitLab(一种Web界面)。
                        • 了解“集中式版本控制器”和“分布式版本控制器”的区别,并说服同事们不要再用SVN、CVS或者SourceSafe等老旧的“集中式版本控制器”了。
                        • 开设一个GitHub账户。如果你不喜欢Git,就用BitBucket等。
                      10. 持续集成

                        自己(或者为你们实验室)搭建一个持续集成(Continuous Integration)服务器,如Jenkins,定期编译你的程序。建议同时使用Git等分布式版本控制器。

                        • 如果你做开源软件,试试GitHub和Travis。
                      11. 零碎工具

                        淘一淘java.nio.files里面有什么好用的东东,然后再淘一淘Apache Commons Lang和Commons IO里有什么好用的工具。Commons Logging就不要再用了,用SLF4j和Logback。

                      12. XML

                        学学XML、DOM、XPath。XML这东西到处都可能用到。也可以用它写自己的配置文件。

                        • 如果觉得不舒服了,就学学JSON和YAML。
                        • 如果还是不舒服,就学学文本文件解析。
                      13. 语法分析和编译器

                        学学Antlr或者别的Parser Generator的用法

                        • 如果觉得舒服,自己写一个计算器。
                        • 如果还觉得舒服,自己写一种Domain-Specific Language (DSL)。
                      14. 高效容器

                        学学FastUtil或者Trove,如果你需要进行大量数值运算的话。

                      15. 分布式计算

                        学学MapReduce的思想以及它的实现。

                        • 如果还舒服,学学Scala语言以及号称比MapReduce快得多的Apache Spark。
                      16. 进程间通信

                        看看ActiveMQ、MINA和RMI。

                      17. 其他语言(JVM)

                        学习另一门跑在JVM上的语言或者实现(如Groovy、Scala、Clojure、JRuby、Jython、JavaScript……)

                      18. 其他语言(非JVM)

                        学习另一门通用脚本语言(如Python、Ruby,其实perl也行,但不推荐),知道什么时候Java不是最好的选择。

                      19. Java语言和Java虚拟机

                        通读一遍(一目十行地读,不用细读)Java Language Specification,以及Java Virtual Machine Specification。

                        • 了解以下解释器(interpreter)、编译器(compiler)、即时编译器(just-in-time compiler)和优化器(optimiser)的概念。
                        • 如果对编译器的话题不感到畏惧,了解一下method JIT和tracing JIT的概念和区别。
                      20. 内存管理

                        学学垃圾回收的几种基本算法,包括mark-sweep、mark-compact、semi-space、generational、mark-region等,各自的性能,以及为什么朴素的reference counting是不完整的。知道为什么finalizer性能很糟糕,而且标准并不要求finalizer在程序退出前一定会执行。

                        • 如果还舒服,了解一下如何设置Java虚拟机的堆大小限制(如HotSpot虚拟机的-Xmx选项等)。
                        • 了解一下Java里的WeakReference以及SoftReference和PhantomReference,以及它们什么时候有用,以及为什么它们实现起来有些困难。
                        • 如果有精力,了解一下Hotspot虚拟机的内存管理算法是什么样的。
                      21. 动态装载

                        学学Java的动态装载(class loading)

                        • 如果还舒服的话,学学OSGI以及它的一种实现(如Felix或者Equinox)
                        • 如果仍然很舒服的话,学学写基于Eclipse平台的程序。不是Eclipse集成开发环境,只是利用他们的图形框架,写自己的应用程序。
                        • 如果还觉得舒服的话,写Eclipse集成开发环境的插件。
                      22. 本地/外语接口

                        学习一下Java Native Interface(JNI),试着写一个Java和C语言混合编程的程序。

                        • 如果觉得不舒服了或者觉得欲仙欲死,就学一学Java Native Access(JNA),试一试不用任何胶水代码而从Java直接装载C库,直接调用C函数。
                        • 如果连JNA也懒得学,就学一学SWIG,自动生成绑定。
                        • 如果觉得舒服,就学一学Java Virtual Machine Tooling Interface(JVMTI),用C程序来监视JVM的状态。
                      23. 密码学

                        学一学密码学,包括编码、密码分析、攻击、对称密钥、公钥系统、数字签名、哈希算法等,看看Java有没有实现。

                        • 如果觉得有点不舒服(你应该不会觉得舒服吧,除非你是学密码学的,要不然总会觉得自己写的程序有安全漏洞),就写一个“人品计算器”来放松一下,要求每次输入同一个姓名,得到的人品值是固定的,但又要让人无法用别人的人品值猜自己的人品值。
                      24. 移动终端

                        学一学Android开发。

                        • 如果有精力的话,看看Dalvik虚拟机是怎么回事。
                        • 建议买一个iPhone或者iPad,或许你再也不想用Android手机或者平板了。
                      25. 历史

                        如果觉得有些无聊,就去挖一挖历史上比较火的可能和Java相关技术,比如:

                        • Applet,想想它比起html5+css3+javascript的缺点在哪里。
                        • AWT、Swing,想想为什么很少有人用Java写图形界面程序。你觉得Swing的程序看上去舒服吗?中国人和残疾人喜欢用Swing程序吗?
                        • JNDI,想想它比起Spring Bean Container的缺点在哪里。
                        • JSP,想想它比起MVC结构的缺点在哪里。
                        • WSDL/SOAP,把它们和XML-RPC、RESTful Web Service比较一下。
                        • XSLT,以及为什么它是图灵完备的。可是它真的比Java本身更好用吗?
                        • Log4j、java.util.logging、Apache Commons Logging,各自有什么问题,以及Log4j的作者本人为什么又开发了SLF4j和Logback?
                        • Java最早是为什么设计的?
                        • Type erasure是怎么回事?为什么ArrayList<int>不行但ArrayList<Integer>就可以?挖一挖历史。

                      其实Java不算完全面向对象的语言。Java更偏实用性,很多控制流(if语句、while循环、for循环等)来自面向过程的语言;基本数据类型(int, char, double等)也不是对象。但另一些语言,比如SmallTalk,更偏向纯粹的面向对象的设计,包括基本的数据类型都是对象,if/while/for等也用对象和方法来实现。比如:

                      基本数据类型也是对象,可以接受消息(即方法),比如:

                      (a + b) sqrt

                      这里面,a+b其实是向a发送“+”消息,参数是b。sqrt也是一个消息,发给一个数。

                      if分支是这样做的:

                      (x < y) ifTrue: [ 
                             max := y. 
                             i := j 
                           ] ifFalse: [ 
                             max := x. 
                             i := k 
                           ]

                      ifTrue:ifFalse: 是一个Boolean对象的一个方法,取两个参数,每个是一个“块”,分别在真和假的情况下执行。

                      还有while循环是这样做的:

                      [i < 100] whileTrue: [ 
                             sum := sum + i. 
                             i := i + 1 
                           ]

                      whileTrue是“块”的一个方法,每次对块求值,如果是真,就反复执行第一个参数(也是“块”)。

                      所以,相对其他面向对象的语言,Java并不算很“面向对象”。所以需要补充一些对面向对象语言的了解。

                      文/Jabari(简书作者)
                      原文链接:http://www.jianshu.com/p/d51551b0a8ba
                      著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

                      Nginx与Tomcat整合

                      因为nginx处理静态页面的速度很快,并且是免费的,它还可以配置负载均衡的服务器集群来搭建多个tomcat,所以nginx+tomcat是企业搭 建javaee项目很好的选择。nginx主要是通过反向代理的方法将jsp,jspx后缀或者是javaee框架设置的特定的页面 (.do,.action)请求来交给tomcat处理,自己处理.html,.css或者是一些图片和flash。

                      Nginx与Tomcat整合的好处如下所示:

                      ◆静态分离,加快用户访问网站的速度。

                      ◆整个负载均衡层和Web层的工作流程为LVS/DR+Keeaplived→Nginx反向代理(动静分离)→Tomcat集群,可以保证整个网站不会因为某一台LVS或Nginx+tomcat机器挂掉而影响网站的运营。

                      ◆Nginx稳定,宕机的可能性微乎其乎。

                      配置很简单,自己本身监听80端口过来的所有请求,如果发现是.jsp或者是.do后缀的文件请求就交给监听8080端口的tomcat来处理,配置如下:

                      server
                      {
                                      listen       80;#定义访问的端口号
                                      server_name www.myhost.com;  #定义访问的域名
                      index index.html index.htm index.jsp default.html default.htm default.php;#默认的根目录访问文件
                                      root  /home/wwwroot/www.myhost.com;#定义服务器访问的默认根目录
                                      location ~ \.(jsp|jspx|do)?$ #tomcat的访问文件后缀
                      {
                                                      proxy_pass http://127.0.0.1:8080;#反向代理到tomcat监听的端口
                      include proxy.conf
                      }
                                      location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
                      {
                                                      expires      30d;
                      }
                                      location ~ .*\.(js|css)?$
                      {
                                                      expires      12h;
                      }
                                      access_log  /home/wwwlogs/www.myhost.com.log  www.myhost.com;
                      }

                      这个是nginx最简单的配置,如果有更多的需求需要参考别的地方。

                      这种默认的配置方法写java代码 request.getRemoteAddr()是获取不到用户访问的真实ip的。只能得到你自己服务器的ip 地址,因为nginx转发了请求。注意上面代码中我在 proxy_pass http://127.0.0.1:8080 下面配置了include proxy.conf,所以你需要在nginx目录里proxy.conf里面配置一些东西。

                      proxy_connect_timeout 300s;
                      proxy_send_timeout   900;
                      proxy_read_timeout   900;
                      proxy_buffer_size    32k;
                      proxy_buffers     4 32k;
                      proxy_busy_buffers_size 64k;
                      proxy_redirect     off;
                      proxy_hide_header  Vary;
                      proxy_set_header   Accept-Encoding ”;
                      proxy_set_header   Host   $host;
                      proxy_set_header   Referer $http_referer;
                      proxy_set_header   Cookie $http_cookie;
                      proxy_set_header   X-Real-IP  $remote_addr;
                      proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;#后端的Web服务器可以通过X-Forwarded-For获取用户真实IP

                      proxy.conf文件配置如上,当然还配置了一些response请求头里面的东西,你可以都加进去。然后你用java代码这个req.getHeader(“X-Forwarded-For”);方法就能获取用户的真实ip了。

                      通过以上的配置nginx这一块就弄好了,你还需要更改一下tomcat的server.xml文件,把tomcat解析javaee项目的目录地 址改成和nginx的目录一致。打开tomcat/conf/server.xml文件,把Host标签appBase属性改成nginx配置里面的 root默认路径。

                      <Host name=”localhost”  appBase=”/home/wwwroot/www.myhost.com”
                      unpackWARs=”true” autoDeploy=”true” />

                      以上nginx+tomcat就配置好了,重启tomcat刷新下nginx配置文件,然后把javaee项目放在/home/wwwroot/www.myhost.com目录就可以用80端口测试使用了。

                      详细操作:

                      一、安装Tomcat和JDK

                      1、上传apache-tomcat-6.0.18.tar.gz和jdk-6u12-linux-i586.bin至/usr/local
                      2、执行如下命令安装tomcat:

                      #cd /usr/local

                      #tar zxvf apache-tomcat-6.0.18.tar.gz

                      解压完成后将apache-tomcat-6.0.18重命名为tomcat
                      3、执行如下命令安装JDK:

                      #./jdk-6u12-linux-i586.bin

                      4、配置环境变量:
                      编辑/etc下的profile文件,加上如下内容:

                      JAVA_HOME="/usr/local/jdk1.6.0_12"

                      CLASS_PATH="$JAVA_HOME/lib:$JAVA_HOME/jre/lib"

                      PATH=".:$PATH:$JAVA_HOME/bin "

                      CATALINA_HOME="/usr/local/tomcat"

                      export JAVA_HOME CATALINA_HOME

                      5、启动tomcat并输入http://localhost:8080,如果看到猫的页面即tomcat和jdk安装成功
                      6、新建文件目录/home/www为网站存放目录,设置server.xml文件,在Host name=”localhost”处将appBase=的指向路径改为/home/www/web
                      7、创建index.jsp至/home/www/web/ROOT,内容为:“My web!”  

                      二、安装Nginx
                      1、上传nginx-0.7.63.tar.gz至/usr/local

                      2、执行如下命令解压nginx:

                      #cd /usr/local

                      #tar zxvf  nginx-0.7.63.tar.gz

                      3、编译安装nginx

                      #cd nginx-0.7.63

                      #./configure --with-http_stub_status_module --with-http_ssl_module  #启动server状态页和https模块

                      执行完后会提示一个错误,说缺少PCRE library 这个是HTTP Rewrite 模块,也即是url静态化的包
                      可上传pcre-7.9.tar.gz,输入如下命令安装:

                      #tar zxvf pcre-7.9.tar.gz

                      #cd pcre-7.9

                      #./configure

                      #make

                      #make install

                      安装pcre成功后,继续安装nginx

                      #cd nginx-0.7.63

                      #./configure

                      #make

                      #make install

                      4、nginx安装成功后的安装目录为/usr/local/nginx
                      在conf文件夹中新建proxy.conf,用于配置一些代理参数,内容如下:

                      #!nginx (-) 

                      # proxy.conf 

                      proxy_redirect          off;

                      proxy_set_header        Host $host;

                      proxy_set_header        X-Real-IP $remote_addr;  #获取真实ip

                      #proxy_set_header       X-Forwarded-For   $proxy_add_x_forwarded_for; #获取代理者的真实ip

                      client_max_body_size    10m;

                      client_body_buffer_size 128k;

                      proxy_connect_timeout   90;

                      proxy_send_timeout      90;

                      proxy_read_timeout      90;

                      proxy_buffer_size       4k;

                      proxy_buffers           4 32k;

                      proxy_busy_buffers_size 64k;

                      proxy_temp_file_write_size 64k;

                      编辑安装目录下conf文件夹中的nginx.conf,输入如下内容

                      #运行nginx所在的用户名和用户组

                      #user  www www; 

                      #启动进程数

                      worker_processes 8;

                      #全局错误日志及PID文件

                      error_log  /usr/local/nginx/logs/nginx_error.log  crit;

                      pid        /usr/local/nginx/nginx.pid;

                      #Specifies the value for maximum file descriptors that can be opened by thisprocess.

                      worker_rlimit_nofile 65535;

                      #工作模式及连接数上限

                      events

                      {

                      use epoll;

                      worker_connections 65535;

                      }

                      #设定http服务器,利用它的反向代理功能提供负载均衡支持

                      http

                      {

                      #设定mime类型

                      include       mime.types;

                      default_type  application/octet-stream;

                      include /usr/local/nginx/conf/proxy.conf;

                      #charset  gb2312;

                      #设定请求缓冲    

                      server_names_hash_bucket_size 128;

                      client_header_buffer_size 32k;

                      large_client_header_buffers 4 32k;

                      client_max_body_size 8m;

                      sendfile on;

                      tcp_nopush     on;

                      keepalive_timeout 60;

                      tcp_nodelay on;

                      #  fastcgi_connect_timeout 300;

                      #  fastcgi_send_timeout 300;

                      #  fastcgi_read_timeout 300;

                      #  fastcgi_buffer_size 64k;

                      #  fastcgi_buffers 4 64k;

                      #  fastcgi_busy_buffers_size 128k;

                      #  fastcgi_temp_file_write_size 128k;

                      #  gzip on;

                      #  gzip_min_length  1k;

                      #  gzip_buffers     4 16k;

                      #  gzip_http_version 1.0;

                      #  gzip_comp_level 2;

                      #  gzip_types       text/plain application/x-javascript text/css application/xml;

                      #  gzip_vary on;

                      #limit_zone  crawler  $binary_remote_addr  10m;

                      ###禁止通过ip访问站点

                      server{

                      server_name _;

                      return 404;

                      }

                      server

                      {

                      listen       80;

                      server_name  localhost;

                      index index.html index.htm index.jsp;#设定访问的默认首页地址

                      root  /home/www/web/ROOT;#设定网站的资源存放路径

                      #limit_conn   crawler  20;    

                      location ~ .*.jsp$ #所有jsp的页面均交由tomcat处理

                      {

                      index index.jsp;

                      proxy_pass http://localhost:8080;#转向tomcat处理

                      }

                      location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ #设定访问静态文件直接读取不经过tomcat

                      {

                      expires      30d;

                      }

                      location ~ .*\.(js|css)?$

                      {

                      expires      1h;

                      }    

                      #定义访问日志的写入格式

                      log_format  access  '$remote_addr - $remote_user [$time_local] "$request" '

                      '$status $body_bytes_sent "$http_referer" '

                      '"$http_user_agent" $http_x_forwarded_for';

                      access_log  /usr/local/nginx/logs/localhost.log access;#设定访问日志的存放路径

                      }

                      }

                      5、修改/usr/local/nginx/conf/nginx.conf配置文件后,请执行以下命令检查配置文件是否正确:

                      #/usr/local/nginx/sbin/nginx -t

                      如果屏幕显示以下两行信息,说明配置文件正确:

                      the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok

                        the configuration file /usr/local/nginx/conf/nginx.conf was tested successfully

                      如果提示unknown host,则可在服务器上执行:ping www.baidu.com如果也是同样提示unknown host则有两种可能:
                          a、服务器没有设置DNS服务器地址,查看/etc/resolv.conf下是否设置,若无则加上
                          b、防火墙拦截

                      6、启动nginx的命令

                      #/usr/local/nginx/sbin/nginx

                      这时,输入以下命令查看Nginx主进程号:

                      ps -ef | grep "nginx: master process" | grep -v "grep" | awk -F ' ' '{print $2}'

                      7、停止nginx的命令

                      #/usr/local/nginx/sbin/nginx -s stop

                      8、在不停止Nginx服务的情况下平滑变更Nginx配置
                      a、修改/usr/local/nginx/conf/nginx.conf配置文件后,请执行以下命令检查配置文件是否正确:

                      /usr/local/nginx/sbin/nginx -t

                        如果屏幕显示以下两行信息,说明配置文件正确:

                        the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok

                        the configuration file /usr/local/nginx/conf/nginx.conf was tested successfully

                      b、这时,输入以下命令查看Nginx主进程号:

                      ps -ef | grep "nginx: master process" | grep -v "grep" | awk -F ' ' '{print $2}'

                      屏幕显示的即为Nginx主进程号,例如:
                        6302
                        这时,执行以下命令即可使修改过的Nginx配置文件生效:

                      kill -HUP 6302

                      或者无需这么麻烦,找到Nginx的Pid文件:

                      kill -HUP `cat /usr/local/nginx/nginx.pid`

                      9、nginx启动好后启动tomcat,此时输入http://主机ip地址即可看到“My web!”