C# 3.0新语言特性和改进

C# 3.0新语言特性和改进包括:

  • 自动属性(Auto-Implemented Properties)
  • 隐含类型局部变量(Local Variable Type Inference)
  • 匿名类型(Anonymous Types)
  • 对象与集合初始化器(Object and Collection Initializers)
  • 扩展方法(Extension Methods)
  • Lambda表达式和Lambda表达式树 (Lambda Expression and Lambda Expression Trees)

自动属性(Auto-Implemented Properties)

自动属性可以避免原来这样我们手工声明一个私有成员变量以及编写get/set逻辑,在VS2008中可以像下面这样编写一个类,编译器会自动地生成私有变量和默认的get/set 操作。你也可以分别定义get和set的“protected”等访问级别。

在.Net2.0框架下,我们可以这样写一个User类:

public class User{
    private int _id;
    private string _name;
    private int _age;
    public int Id
    {
        get { return _id; }
        set { _id = value; }
    }
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
    public int Age
    {
        get { return _age; }
        set { _age = value; }
    }
}

现在,可以这样简化:

public class User{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

像上面这样的空的get/set属性的话,它会自动为你在类中生成一个私有成员变量,对这个变量实现一个公开的getter 和setter。我们可以使用.NET开发环境所提供的ildasm.exe(IL代码反汇编器)工具来分析程序集或者模块的内容。我就不贴图了。

隐含类型局部变量(Local Variable Type Inference)

C#3.0引进了var这个新关键字,在声明局部变量时可用于替代原先的类型名,即当一个变量声明标识为var类型并且该范围域中没有var名称类型存在,那么这个声明就称为隐含类型局部变量。如下(等同于//后面的显式声明):

var i = 5;//int var j = 23.56;//double var k = "C Sharp";//string var x;//错误 
var y = null;//错误 var z = { 1, 2, 3 };//错误

在调试状态下,编译器解释如下

隐含类型局部变量调试

隐含类型局部变量要点

  1. var为关键字,可以根据后面的初始化语句自动推断类型,这个类型为强类型。
  2. 初始化语句必须为表达式,不可以为空。且编译时可以推断类型。一旦初始化之后,只可以存储这种类型。
  3. var声明的仅限于局部变量,不可用于字段。亦可以用于for,foreach,using 等语句中。
  4. 数组也可以作为隐含类型。
  5. 初始化语句不能是一个自身的对象或者集合初始化器,但是他可以是包含一个对象或者初始化器的一个new表达式。
  6. 如果局部变量声明包含了多个声明符,其类型必须相同。

匿名类型(Anonymous Types)

匿名类型允许定义行内类型,无须显式定义类型。常和var配合使用来声明匿名类型。

var p1 = new { Id = 1, Name = "YJingLee", Age = 22 };
//属性也不需要申明 var p2 = new { Id = 2, Name = "XieQing", Age = 25 };
p1 = p2;//p1,p2结构相同,可以互相赋值

匿名类型调试

在这里编译器会认为p1,p2相当于:

public class SomeType {
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

那么数组怎么定义呢?使用"new[]"关键字来声明数组,加上数组的初始值列表。像这样:

var intArray = new[] { 2, 3, 5, 6 };
var strArray = new[] { "Hello", "World" };
var anonymousTypeArray = new[] 
{ 
    new { Name = "YJingLee", Age = 22 }, 
    new { Name = "XieQing", Age = 25 } 
};
var a = intArray[0];
var b = strArray[0];
var c = anonymousTypeArray[1].Name;

匿名数组调试

匿名类型要点

  1. 可以使用new关键字调用匿名初始化器创建一个匿名类型的对象。
  2. 匿名类型直接继承自System. Object。
  3. 匿名类型的成员是编译器根据初始化器推断而来的一些读写属性。

对象与集合初始化器(Object and Collection Initializers)

对象初始化器 (Object Initializers) :

.NET2.0框架中的类型非常依赖于属性。当生成对象实例和使用新的类型时,在.Net2.0时候我们像这样写:

User user = new User();
user.Id = 1;
user.Name = "YJingLee";
user.Age = 22;

在VS2008中,编译器会自动地生成合适的属性setter代码,使得原来几行的属性赋值操作可以在一行完成。我们可以这样简化:像这样,对象初始化器由一系列成员对象组成,其对象必须初始化,用逗号间隔,使用{}封闭。

User user = new User { Id = 1, Name = "YJingLee", Age = 22 };

又例如,我把二个人加到一个基于泛型的类型为User的List集合中:

List<User> user = new List<User>{
    new User{Id=1,Name="YJingLee",Age=22},
    new User{Id=2,Name="XieQing",Age=25},
};

对象初始化器调试

如果有相同名字和类型的两个对象初始化器将会产生相同的实例,可以相互赋值。例如:

User user = new User { Id = 1, Name = "YJingLee", Age = 22 };
User user2 = new User { Id = 2, Name = "XieQing", Age = 25 };
user = user2; 

除了在初始化类时设置简单的属性值外,对象初始化器特性也允许我们设置更复杂的嵌套(nested)属性类型。例如我们可以在上面定义的User类型同时拥有一个属于Address类型的叫“Address”的属性:

User user = new User {
    Id = 1,
    Name = "YJingLee",
    Age = 22,
    Address = new Address     {
        City = "NanJing",
        Zip = 21000
    }
};

集合初始化器(Collection Initializers):

集合初始化器由一系列集合对象组成,用逗号间隔,使用{}封闭。
集合初始化器可以简化把几个对象一起添加到一个集合,编译器会自动为你做集合插入操作。例如我把七个数加到一个基于泛型的类型为int的List集合中

List<int> num = new List<int> { 0, 1, 2, 6, 7, 8, 9 };

对象与集合初始化器要点

  1. 对象初始化器实际上利用了编译器对对象中对外可见的字段和属性进行按序赋值。
  2. 对象初始化器允许只给一部分属性赋值,包括internal访问级别
  3. 对象初始化器可以结合构造函数一起使用,并且构造函数初始化先于对象初始化器执行。
  4. 集合初始化器会对初始化器中的元素进行按序调用ICollection<T>.Add(T)方法。
  5. 注意对象初始化器和集合初始化器中成员的可见性和调用顺序。
  6. 对象与集合初始化器同样是一种编译时技术。

C# 3.0新语言特性和改进包括:

  • 自动属性(Auto-Implemented Properties)
  • 隐含类型局部变量(Local Variable Type Inference)
  • 匿名类型(Anonymous Types)
  • 对象与集合初始化器(Object and Collection Initializers)
  • 扩展方法(Extension Methods)
  • Lambda表达式和Lambda表达式树 (Lambda Expression and Lambda Expression Trees)

扩展方法(Extension Methods)

往往我们需要对CLR类型进行一些操作,但苦于无法扩展CLR类型的方法,只能创建一些helper方法,或者继承类。我们来修改上面的User类:

public class User{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Read()
    {
        return "Id:" + Id + "姓名:" + Name + "年龄:" + Age;
    }
}

然后调用

var user = new { Id = 1, Name = "YJingLee", Age = 22 };var str = user.Read();

现在有了扩展方法就方便多了。

扩展方法允许开发人员往一个现有的CLR类型的公开契约(contract)中添加新的方法,而不用生成子类或者重新编译原来的类型。扩展方法有助于把今天动态语言中流行的对duck typing的支持之灵活性,与强类型语言之性能和编译时验证融合起来。——引用Scott博文

扩展方法是可以通过使用实例方法语法调用的静态方法。效果上,使得附加的方法扩展已存在类型和构造类型成为可能。他可以对现有类功能进行扩充,从而使该类型的实例具有更多的方法(功能)。
扩展方法允许我们在不改变源代码的情况下扩展(即添加不能修改)现有类型中的实例方法。

扩展方法给我们一个怎样的思路呢?我们一步一步做一下!
首先声明扩展方法:通过指定关键字this修饰方法的第一个参数。注意扩展方法仅可声明在静态类中。扩展方法具备所有常规静态方法的所有能力,可以使用实例方法语法来调用。接着就可以调用扩展方法了。下面通过一个具体的实例分析一下:
例如我们要检查一个字符串变量是否是合法的电子邮件地址?在.Net2.0框架下像这样:

var email = "leeyongjing@gmail.com";if (EmailValidator.IsValid(email))
{
    Response.Write("YJingLee提示:这是一个正确的邮件地址");
}

而使用扩展方法的话,我可以添加“IsValidEmailAddress()”方法到string类本身中去,该方法返回当前字符串实例是否是个合法的字符串。

if (email.IsValidEmailAddress())
{
    Response.Write("YJingLee提示:这是一个正确的邮件地址");
}

我们是怎么把这个IsValidEmailAddress()方法添加到现有的string类里去的呢?先定义一个静态类,再定义“IsValidEmailAddress”这个静态的法来实现的。

public static class Extensions//静态类{
    public static bool IsValidEmailAddress(this string s)
    //静态方法和this
    {
        Regex regex = new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$");
        return regex.IsMatch(s);
    }
}

注意,上面的静态方法在第一个类型是string的参数变量前有个“this”关键词,这告诉编译器,这个特定的扩展方法应该添加到类型为“string”的对象中去。然后在IsValidEmailAddress()方法实现里,我可以访问调用该方法的实际string实例的所有公开属性/方法/事件,取决于它是否是合法电子邮件地址来返回true/false。

扩展方法不仅能够应用到个别类型上,也能应用到.NET框架中任何基类或接口上。即可用于整个.NET框架丰富的可组合的框架层扩展。

扩展方法要点

  1. 扩展方法的本质为将实例方法调用在编译期改变为静态类中的静态方法调用。事实上,它确实拥有静态方法所具有的所有功能。
  2. 扩展方法的作用域是整个namespace可见的,并且可以通过using namespace来导入其它命名空间中的扩展方法。
  3. 扩展方法的优先级:现有实例方法优先级最高,其次为最近的namespace下的静态类的静态方法,最后为较远的namespace下的静态类的静态方法。
  4. 扩展方法是一种编译时技术,注意与反射等运行时技术进行区别,并慎重使用。

Lambda表达式和Lambda表达式树 (Lambda Expression and Lambda Expression Trees)

Lambda表达式

我们从“所有字符串查找包含YJingLee子字符串”说起。在C# 2.0中,匿名方法允许我们以内联的方式来实现委托实例,它提供强大的函数式编程语言,但是标记显得相当的冗长和带有强制性。我们使用C# 2.0 中的匿名方法查找,代码如下:

var inString = list.FindAll(delegate(string s)
{ return s.Indexof("YJingLee") >= 0; });

现在可以使用C# 3.0带来的Lambda表达式允许我们使用一种更接近人的思维、更自然的方式来实现类似于匿名方法同样的效果,看下面的代码多么简洁:

var inString = list.FindAll(s => s.Indexof("YJingLee") >= 0);

Lambda表达式格式:(参数列表)=>表达式或语句块
具体意义:定义Lambda接受参数列表,运行表达式或语句块返回表达式或语句块的值传给这个参数列表。

Lambda表达式参数类型可以是隐式类型或显式类型。在显式列表中,每个参数的类型是显式指定的,在隐式列表中,参数的类型由Lambda表达式出现的语境自动推断类型。
Lambda表达式的参数列表可以有一个或多个参数,或者无参数。在有单一的隐型参数的lambda表达式中,圆括号可以从参数列表中省略。
例如:

(x, y) => x * y;//多参数,隐式类型=>表达式x => x * 10;
//单参数,隐式类型=>表达式x => { return x * 10; }; 
//单参数,隐式类型=>语句块(int x) => x * 10;
//单参数,显式类型=>表达式(int x) => { return x * 10; };
//单参数,显式类型=>语句块() => Console.WriteLine(); //无参数

下面看这个例子:
在前面的帖子中,我们写了一个User类及增加了2个人,接下来,我们使用由LINQ提供的新的Where和Average方法来返回集合中的人的一个子集,以及计算这个集合中的人的平均年龄:

List<User> user = new List<User>{
    new User{Id=1,Name="YJingLee",Age=22},
    new User{Id=2,Name="XieQing",Age=25},
};//获取特定人时所用的过滤条件,p参数属于User类型
var results = user.Where(p => p.Name == "YJingLee").ToList();
//用User对象的Age值计算平均年龄
var average = user.Average(p => p.Age);

效果图如下:

Lambda表达式

对这个Lambda表达式做个简要分析:

var resultsdelegate = user.Where(delegate(User p)
{
    return p.Name == "YJingLee";// 返回一个布尔值});
var averagedelegate = user.Average(delegate(User p)
{
    return p.Age;
});

Lambda表达式简要分析

Lambda表达式L可以被转换为委托类型D,需要满足以下条件:
L的参数类型要与D的参数个数相等,类型相同,返回类型相同,无论是表达式,还是语句块。注意隐式类型要参与类型辨析。

Lambda表达式树

Lambda表达式树允许我们像处理数据(比如读取,修改)一样来处理Lambda表达式。我以一个例子简单说明:

Expression<Func<int, bool>> filter = n => (n * 3) < 5;
BinaryExpression lt = (BinaryExpression)filter.Body;
BinaryExpression mult = (BinaryExpression)lt.Left;
ParameterExpression en = (ParameterExpression)mult.Left;
ConstantExpression three = (ConstantExpression)mult.Right;
ConstantExpression five = (ConstantExpression)lt.Right;
var One = filter.Compile();Console.WriteLine("Result: {0},{1}", One(5), One(1));
Console.WriteLine("({0} ({1} {2} {3}) {4})", lt.NodeType,

mult.NodeType, en.Name, three.Value, five.Value);

效果图如下:

Lambda表达式树

Lambda表达式和Lambda表达式树要点

  1. Lambda表达式的参数类型可以忽略,因为可以根据使用的上下文进行推断。
  2. Lambda表达式的主体(body)可以是表达式,也可以是语句块。
  3. Lambda表达式传入的实参将参与类型推断,以及方法重载辨析。
  4. Lambda表达式和表达式体可以被转换为表达式树。
  5. 表达式树允许lambda表达式能够代表数据结构替代表示为执行代码。

好了,我在这里简单的把C# 3.0新语言特性和改进说了一下,接下来,正式进入这个系列的主题部分——LINQ。为 了让大家了解,我换一种手法来写,从一条一条LINQ to SQL语句分析来贯穿LINQ的知识点。一起体验LINQ带给我们的乐趣。

发表在 article | 32条评论

.NET 客户端连接Redis 介绍

C#写的客户端类型主要有:

ServiceStack.Redis ★  https://github.com/ServiceStack/ServiceStack.Redis
Booksleeve ★   http://code.google.com/p/booksleeve/
Sider  http://nuget.org/List/Packages/Sider
TeamDev Redis Client  http://redis.codeplex.com/
redis-sharp   https://github.com/migueldeicaza/redis-sharp

加星号的是使用率高的项目。参考:http://redis.io/clients

ServiceStack.Redis为例

引入到项目中,并添加如下名空间引用(仅限本文):

using ServiceStack.Common.Extensions;
using ServiceStack.Redis;
using ServiceStack.Redis.Generic;
using ServiceStack.Text;
using ServiceStack.Redis.Support;

注:ServiceStackRedis封装了大量方法和对象,这里只摘有代表性的内容介绍,更多内容参见其官方文档。

声明一个客户端对象:
protected RedisClient Redis = new RedisClient("127.0.0.1", 6379);//redis服务IP和端口

一 .基本KEY/VALUE键值对操作:
1. 添加/获取:

List<string> storeMembers =new List<string>();
storeMembers.ForEach(x
=> Redis.AddItemToList("additemtolist", x));

注:也可直接使用AddRangeToList方法将一组数据装入如:

Redis.AddRangeToList("addarrangetolist", storeMembers);

2. 获取数据

var members = Redis.GetAllItemsFromList("additemtolist");
members.ForEach(s
=> Response.Write("<br/>additemtolist :"+ s));

3. 获取指定索引位置数据

var item = Redis.GetItemFromList("addarrangetolist", 2);

4. 移除:

var list = Redis.Lists["addarrangetolist"];
list.Clear();
//清空
list.Remove("two");//移除指定键值
list.RemoveAt(2);//移除指定索引位置数据

二.存储对象:

publicclass UserInfo
{
publiclong Id { set; get; }
publicstring UserName { get; set; }
publicint Age { get; set; }
}

1.通常方式(底层使用json序列化):

Redis.Set<UserInfo>("userinfo", new UserInfo() { UserName ="李四", Age =45 });
UserInfo userinfo
= Redis.Get<UserInfo>("userinfo");

注:当然上面方式也适合于基本类型,如:

Redis.Set<int>("my_age", 12);//或Redis.Set("my_age", 12);
int age = Redis.Get<int>("my_age");

2.object序列化方式存储:

var ser =new ObjectSerializer(); //位于namespace ServiceStack.Redis.Support;
bool result = Redis.Set<byte[]>("userinfo", ser.Serialize(new UserInfo() { UserName ="张三", Age =12 }));
UserInfo userinfo
= ser.Deserialize(Redis.Get<byte[]>("userinfo")) as UserInfo;
//也支持列表
Redis.Set<byte[]>("userinfolist_serialize", ser.Serialize(userinfoList));
List
<UserInfo> userList = ser.Deserialize(Redis.Get<byte[]>("userinfolist_serialize")) as List<UserInfo>;

需要说明的是在测试过程中发现JSON序列化的效率要比object序列化高一些。

三.存储表格对象,比如:

using (var redisUsers = Redis.GetTypedClient<UserInfo>())
{
redisUsers.Store(
new UserInfo { Id = redisUsers.GetNextSequence(), UserName ="daizhj", Age =12 });
redisUsers.Store(
new UserInfo { Id = redisUsers.GetNextSequence(), UserName ="daizhenjun", Age =13 });

var allUsers = redisUsers.GetAll();//就像操作ado对象一样,可以进行CRUD等操作
allUsers.ForEach(s => Response.Write("<br/>user :"+ s.UserName +" age:"+ s.Age));
}

四.使用客户端链接池模式提升链接速度:

publicstatic PooledRedisClientManager CreateManager(string[] readWriteHosts, string[] readOnlyHosts)
{
//支持读写分离,均衡负载
returnnew PooledRedisClientManager(readWriteHosts, readOnlyHosts, new RedisClientManagerConfig
{
MaxWritePoolSize
=5,//“写”链接池链接数
MaxReadPoolSize =5,//“写”链接池链接数
AutoStart =true,
});
}

声明链接池对象(这里只使用一个redis服务端):

PooledRedisClientManager prcm = CreateManager(newstring[] { "127.0.0.1:6379" }, newstring[] { "127.0.0.1:6379" });

List<UserInfo> userinfoList =new List<UserInfo>();
userinfoList.Add(
new UserInfo() { UserName ="pool_daizhj", Age =1 });
userinfoList.Add(
new UserInfo() { UserName ="pool_daizhj1", Age =2 });

从池中获取一个链接:

using (IRedisClient Redis = prcm.GetClient())
{
Redis.Set(
"userinfolist", userinfoList);
List
<UserInfo> userList = Redis.Get<List<UserInfo>>("userinfolist");
}

注:
1.前三种方式我在本地测试发现存取效率从高到底,具体原因还待分析。

2.如只想使用长链接而不是链接池的话,可以直接将下面对象用static方式声明即可:
protected static RedisClient Redis = new RedisClient("127.0.0.1", 6379);

这样在redis服务端显示只有一个客户链接

3.与memcached测试过程中发现,在存储时两者效率接近(使用本文第一种方式),在取数据时memcached速度比redis要快一些(毫秒级差异),这一点并不像网上一些文章所说的那样,看来在实际开发和生产环境下还要以使用背景及结果为准。

发表在 cache | .NET 客户端连接Redis 介绍已关闭评论

Redis指令文档(参考)

Redis指令文档

连接控制
QUIT 关闭连接
AUTH (仅限启用时)简单的密码验证

适合全体类型的命令
EXISTS key 判断一个键是否存在;存在返回 1;否则返回0;
DEL key 删除某个key,或是一系列key;DEL key1 key2 key3 key4
TYPE key 返回某个key元素的数据类型 ( none:不存在,string:字符,list,set,zset,hash)
KEYS pattern 返回匹配的key列表 (KEYS foo*:查找foo开头的keys)
RANDOMKEY 随机获得一个已经存在的key,如果当前数据库为空,则返回空字符串
RENAME oldname newname更改key的名字,新键如果存在将被覆盖
RENAMENX oldname newname 更改key的名字,如果名字存在则更改失败
DBSIZE返回当前数据库的key的总数
EXPIRE设置某个key的过期时间(秒),(EXPIRE bruce 1000:设置bruce这个key1000秒后系统自动删除)注意:如果在还没有过期的时候,对值进行了改变,那么那个值会被清除。
TTL查找某个key还有多长时间过期,返回时间秒
SELECT index 选择数据库
MOVE key dbindex 将指定键从当前数据库移到目标数据库 dbindex。成功返回 1;否则返回0(源数据库不存在key或目标数据库已存在同名key);
FLUSHDB 清空当前数据库中的所有键
FLUSHALL 清空所有数据库中的所有键

处理字符串的命令
SET key value 给一个键设置字符串值。SET keyname datalength data (SET bruce 10 paitoubing:保存key为burce,字符串长度为10的一个字符串paitoubing到数据库),data最大不可超过1G。
GET key获取某个key 的value值。如key不存在,则返回字符串“nil”;如key的值不为字符串类型,则返回一个错误。
GETSET key value可以理解成获得的key的值然后SET这个值,更加方便的操作 (SET bruce 10 paitoubing,这个时候需要修改bruce变成1234567890并获取这个以前的数据paitoubing,GETSET bruce 10 1234567890)
MGET key1 key2 … keyN 一次性返回多个键的值
SETNX key value SETNX与SET的区别是SET可以创建与更新key的value,而SETNX是如果key不存在,则创建key与value数据
MSET key1 value1 key2 value2 … keyN valueN 在一次原子操作下一次性设置多个键和值
MSETNX key1 value1 key2 value2 … keyN valueN 在一次原子操作下一次性设置多个键和值(目标键不存在情况下,如果有一个以上的key已存在,则失败)
INCR key 自增键值
INCRBY key integer 令键值自增指定数值
DECR key 自减键值
DECRBY key integer 令键值自减指定数值

处理 lists 的命令
RPUSH key value 从 List 尾部添加一个元素(如序列不存在,则先创建,如已存在同名Key而非序列,则返回错误)
LPUSH key value 从 List 头部添加一个元素
LLEN key 返回一个 List 的长度
LRANGE key start end从自定的范围内返回序列的元素 (LRANGE testlist 0 2;返回序列testlist前0 1 2元素)
LTRIM key start end修剪某个范围之外的数据 (LTRIM testlist 0 2;保留0 1 2元素,其余的删除)
LINDEX key index返回某个位置的序列值(LINDEX testlist 0;返回序列testlist位置为0的元素)
LSET key index value更新某个位置元素的值
LREM key count value 从 List 的头部(count正数)或尾部(count负数)删除一定数量(count)匹配value的元素,返回删除的元素数量。
LPOP key 弹出 List 的第一个元素
RPOP key 弹出 List 的最后一个元素
RPOPLPUSH srckey dstkey 弹出 _srckey_ 中最后一个元素并将其压入 _dstkey_头部,key不存在或序列为空则返回“nil”

处理集合(sets)的命令(有索引无序序列)
SADD key member增加元素到SETS序列,如果元素(membe)不存在则添加成功 1,否则失败 0;(SADD testlist 3 n one)
SREM key member 删除SETS序列的某个元素,如果元素不存在则失败0,否则成功 1(SREM testlist 3 N one)
SPOP key 从集合中随机弹出一个成员
SMOVE srckey dstkey member 把一个SETS序列的某个元素 移动到 另外一个SETS序列 (SMOVE testlist test 3n two;从序列testlist移动元素two到 test中,testlist中将不存在two元素)
SCARD key 统计某个SETS的序列的元素数量
SISMEMBER key member 获知指定成员是否存在于集合中
SINTER key1 key2 … keyN 返回 key1, key2, …, keyN 中的交集
SINTERSTORE dstkey key1 key2 … keyN 将 key1, key2, …, keyN 中的交集存入 dstkey
SUNION key1 key2 … keyN 返回 key1, key2, …, keyN 的并集
SUNIONSTORE dstkey key1 key2 … keyN 将 key1, key2, …, keyN 的并集存入 dstkey
SDIFF key1 key2 … keyN 依据 key2, …, keyN 求 key1 的差集。官方例子:
key1 = x,a,b,c
key2 = c
key3 = a,d
SDIFF key1,key2,key3 => x,b
SDIFFSTORE dstkey key1 key2 … keyN 依据 key2, …, keyN 求 key1 的差集并存入 dstkey
SMEMBERS key 返回某个序列的所有元素
SRANDMEMBER key 随机返回某个序列的元素

处理有序集合(sorted sets)的命令 (zsets)
ZADD key score member 添加指定成员到有序集合中,如果目标存在则更新score(分值,排序用)
ZREM key member 从有序集合删除指定成员
ZINCRBY key increment member 如果成员存在则将其增加_increment_,否则将设置一个score为_increment_的成员
ZRANGE key start end 返回升序排序后的指定范围的成员
ZREVRANGE key start end 返回降序排序后的指定范围的成员
ZRANGEBYSCORE key min max 返回所有符合score >= min和score <= max的成员 ZCARD key 返回有序集合的元素数量 ZSCORE key element 返回指定成员的SCORE值 ZREMRANGEBYSCORE key min max 删除符合 score >= min 和 score <= max 条件的所有成员

排序(List, Set, Sorted Set)
SORT key BY pattern LIMIT start end GET pattern ASC|DESC ALPHA 按照指定模式排序集合或List

SORT mylist
默认升序 ASC

SORT mylist DESC

SORT mylist LIMIT 0 10
从序号0开始,取10条

SORT mylist LIMIT 0 10 ALPHA DESC
按首字符排序

SORT mylist BY weight_*
SORT mylist BY weight_* GET object_*
SORT mylist BY weight_* GET object_* GET #

SORT mylist BY weight_* STORE resultkey
将返回的结果存放于resultkey序列(List)

持久控制
SAVE 同步保存数据到磁盘
BGSAVE 异步保存数据到磁盘
LASTSAVE 返回上次成功保存到磁盘的Unix时间戳
SHUTDOWN 同步保存到服务器并关闭 Redis 服务器(SAVE+QUIT)
BGREWRITEAOF 当日志文件过长时重写日志文件

远程控制命令
INFO 提供服务器的信息和统计信息
MONITOR 实时输出所有收到的请求
SLAVEOF 修改复制选项

redis目前提供四种数据类型:string,list,set及zset(sorted set)。
* string是最简单的类型,你可以理解成与Memcached一模一个的类型,一个key对应一个value,其上支持的操作与Memcached的操作类似。但它的功能更丰富。
* list是一个链表结构,主要功能是push、pop、获取一个范围的所有值等等。操作中key理解为链表的名字。
* set是集合,和我们数学中的集合概念相似,对集合的操作有添加删除元素,有对多个集合求交并差等操作。操作中key理解为集合的名字。
* zset是set的一个升级版本,他在set的基础上增加了一个顺序属性,这一属性在添加修改元素的时候可以指定,每次指定后,zset会自动重新按新的值调整顺序。可以理解了有两列的mysql表,一列存value,一列存顺序。操作中key理解为zset的名字。

协议
redis目前只有基于TCP的文本协议,与memcache类似,有一些改进。
客户端通常发送
命令 参数… 值字节数rn
值rn

服务端的返回,根据第一个字节,可以判断:
- 错误信息
+ 普通文本信息
$ 变长字节数,$6表示CRLF之后有6个字节的字符
: 返回一个整数
* 返回组数,即*6表示CRLF之后将返回6组变长字符

注意事项:
Key不可包含空格或者回车符
Key不要过长或过短,应使其有意义,如”comment:1234:reply.to”

发表在 cache | Redis指令文档(参考)已关闭评论

Redis使用系列:协议篇

中文命令参考:

   http://redis.readthedocs.org/en/latest/

 

---------------------------------------------------------------------------

Redis从1.2版本开始,设计了一套统一的协议格式,作者讲到自己设计的协议在下面几个方面进行了权衡:
1. 实现简单
2. 快速通过计算机解析
3. 容易让人阅读

如果我们需要自己实现一个Redis客户端程序,有必要了解一下Redis的协议格式。在网络层面,客户端通过TCP连接到Redis服务器(默认端口6379,可以通过配置文件修改),客户端与服务器之间发送的命令以\r\n(CR LF)结尾。

请求协议

Redis请求参数的通用格式如下:

*<参数数量> CR LF  $<第1个参数字节数> CR LF  <参数数据> CR LF  ...  $<第N个参数字节数> CR LF  <参数数据> CR LF

举个例子,要使用SET命令在Redis中存储一条key=mykey,value=myvalue的数据,则客户端发送给Redis的服务器协议如下:

*3  $3  SET  $5  mykey  $7  myvalue

最终发给Redis服务器的二进制数据用字符串表示是:

*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n

应答协议

Redis的应答命令分为不同的种类,每种应答使用不同的表示方式,下面逐一说明。

1. 单行应答:使用“+”开始,后面跟应答字符串,以\r\n结尾,客户端实现给应用程序返回“+”后面的内容,如:

+OK\r\n

2. 错误应答:与单行应答类似,只不过以“-”开始,如:

-(error) ERR unknown command 'INC'\r\n

3. 整数应答:使用“:”开始,后面跟应答内容(表示整数的字符串),以\r\n结尾,如:

:1000\r\n

4. Bulk应答:如使用GET命令获取一个字符串,服务器会使用Bulk应答,使用“$”开始,后面跟应答数据字节数(+\r\n),再加上应答数据,最后以\r\n结尾,如:

$7\r\nmyvalue\r\n

如果没有获取到结果(如请求的Key不存在),服务器将会应答-1,如:

$-1

5. 批量应答:有些命令如LRANGE等,需要返回多个应答值,此时Redis采用与请求命令相同的协议格式发送应答:

*4  $3  foo  $3  bar  $5  hello  $5  world

客户端接收到的二进制数据用字符串表示:

*4\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$5\r\nhello\r\n$5\r\nworld\r\n

如果没有获取到结果,服务器会应答-1,如:

*-1

其他说明

1. Redis支持Pipelining把多个命令打包在一起发送以减少RTT,详细信息请参考官网这篇文章

2. 在Redis 2.2版本中提供了基于C的客户端hiredis(以前也提供,但是2.2版本进行了大规模的重构),在实现一个客户端时是一个很好的参考。

Redis使用系列通过三篇文章:配置文件分析、功能示例和协议,为大家介绍了Redis的使用。接下来是时候去看看Redis的源码,并通过源码分析内部实现,如VM机制、字符串实现等,Redis源码分析系列见。

发表在 cache | Redis使用系列:协议篇已关闭评论

删除 .svn 文件夹的bat

去除.svn文件夹也可以通过svn来操作。TortoiseSVN --> Export

@echo off   
set beginDir
="."  
rem echo Search Dir is 
%beginDir%   
echo.   
for /"tokens=* delims=" %%in ('dir /ad /b/%beginDir% ^| findstr "\\\.svn$"') do (   
 rmdir 
//"%%i"  
 echo 
"%%i"  
)   
echo.   
echo Deleted successful.   
echo.   
pause

发表在 article | 29条评论

配置Microsoft Visual SourceSafe 2005的Internet访问

步骤0:安装前的准备事项

 

服务器端:

因为Internet访问是通过Web Service实现的,所以安装前要先配置安装好IIS。

安装VSS2005好像可以自动安装.Net Framework 2.0,不过,我是事先安装好.Net Framework 2.0并启用Asp.Net 2.0的。

 

客户端:

只有Visual Studio 2005默认支持VSS的Internet访问,所以客户端还要安装VS2005。

 

步骤1:安装VSS2005

 

安装VSS2005一路Next就OK了。服务器和客户端都要安装。

 

步骤2:创建VSS数据库,并启用Internet访问

 

这一步最关键,如果配置没问题就成功了一半。

 

1、 启动Microsoft Visual SourceSafe Administrator

2、 创建VSS数据库

 

一路Next,OK。

 

3、 启用Internet访问

 

  • 选择菜单Server --〉Configure…,弹出Server Configuration对话框

 

  • 给Enable SourceSafe Internet for this computer和Enable SourceSafe Internet for this database打上勾,输入服务器的IP地址。按确定,My God,不行。

 

  • 系统提示要用Share路径访问。重来!
  • 首先到资源管理器,把VSS数据库的路径共享,设置好用户的共享访问权限。
  • 然后再进入Microsoft Visual SourceSafe Administrator
  • 选择菜单File --〉Open SourceSafe Database…,弹出一个对话框
  • 点击Add…按钮,按下一步,在需要指定Location的时候输入""server"vss

  • 最后选择新加的库,点击Open,重新执行步骤1和2。

  • 中间会有一些提示,不管他,回答yes就是了。
  • 没有提示错误的话,你的服务器端就配置好了。

 

 

4、 客户端通过Internet访问

 

  • 安装好VSS2005
  • 打开Visual Studio 2005
  • 选择菜单Tools --〉 Options --〉 Source Control --〉 Plug-in Selection
  • 选择Microsoft Visual SourceSafe (Internet)

  • 选择菜单Tools à Options à Source Control à Plug-in Settings à Advanced…

  • 去掉Always use SSL to connect to the server前面那个勾
  • 随便打开一个项目,选择菜单File à Source Control à Add Project to Source Control
  • 系统打开Open SourceSafe Database对话框
  • 点击Add…按钮
  • 你会发现第二步变成了要输入Address和Folder了。输入服务器的IP地址,和共享的目录名(例如:""server"vss
  • 点击Open,出现登录对话框,输入你在服务器上的账号和密码。

  • 如果成功登录,就会出现Add to SourceSafe Internet对话框。

 

你就可以把项目加入Internet了。

 

如果出现下列错误:

Visual SourceSafe Internet plug-in could not connect to the specified database

Secure communication using SSL needs to be enabled for this database to use your SourceSafe logon name.

Otherwise the database administrator will need to create a SourceSafe user matching your network user name and allow using network names for automatic user log in...

则需要在 Visual SourceSafe中增加user, 其用户名、密码与你登录windows的用户名、密码相同。

发表在 article | 配置Microsoft Visual SourceSafe 2005的Internet访问已关闭评论

rejected by digital signature policy 数字签名策略拒绝

我是在虚拟机中安装Windows Moblie 6.1 Professional SDK的时候报这个错误。

查了一些资料,有的说是因为内存小了导致的。我的虚拟机给它设置的内存是2G,所以不存在内存不足的问题。应该是权限的问题造成的,所以打开本地策略  

由于是新系统,之前没有设置软件策略,这里是一片空白,所以给软件限制策略创建一个新策略。选择右边“对象类型”下面的“强制”。  

“将软件限制策略应用到下列用户”默认是选中的“所有用户”,改为“除本地管理员以外的所有用户”。  

然后重启计算机,再重新安装Windows Moblie 6.1 Professional SDK,问题不再出现。

或者安装系统更新 windows
Server 2003
更新程序(KB973825)

http://support.microsoft.com/kb/973825

发表在 article | 标签为 | rejected by digital signature policy 数字签名策略拒绝已关闭评论

HTTP Error 404.13 - Not Found & IIS7文件上传的最大大小 maxAllowedContentLength,maxRequestLength

当上传一个超过30M的文件时,服务器会重定向至404.13页面,报错如下:

HTTP Error 404.13 - Not Found

The request filtering module is configured to deny a request that exceeds the request content length.

这是由于服务器限制了所能上传文件的最大值。其值在configuration/system.webServer/security/requestFiltering/requestLimits@maxAllowedContentLength setting in the applicationhost.config or web.config file. 中定义。

查看C:\Windows\System32\inetsrv\config目录下的applicationhost.config,可以在system.webServer/security/requestFiltering/中找到requestLimits设置项,若没有,则可以自行添加如下:(这里maxAllowedContentLength的单位为bytes。)

<system.webServer>
   <security>
       <requestFiltering>
              <requestLimits maxAllowedContentLength="40000000" />
       </requestFiltering>
   <security>
<system.webServer>

也可以使用命令行模式修改applicationhost.config为:

%windir%\system32\inetsrv\appcmd set config -section:requestFiltering -requestLimits.maxAllowedContentLength:40000000

经过这个设置后,服务器对上传文件的大小限制将变为40000000bytes了。当然,这个设置是服务器级别的,如果你想在某个站点或者某个应用上限制大小,也可以通过以相同方式进行设置,只不过这次设置的是站点内的Web.config。

但是你要进行此项修改,要确保applicationhost.config中对该项修改的权限已经放开。可通过如下设置进行更改:

modify the overrideModeDefault from "Deny" to "Allow" like so:

<sectionGroup name="system.webServer">
     <section name="requestFiltering" overrideModeDefault="Allow" />
</sectionGroup>

确认修改过applicationhost.config中上述设置以后,再进行如下设置。

找到应用的Web.config,按上述进行修改:

<system.webServer>
   <security>
       <requestFiltering>
              <requestLimits maxAllowedContentLength="40000000" />
       </requestFiltering>
   <security>
<system.webServer>

或者你也可以通过命令行的形式:

%windir%\system32\inetsrv\appcmd set config "Default Web Site/<your app>" -section:requestFiltering -requestLimits.maxAllowedContentLength:40000000

这样,你就能针对某个站点的某个应用进行设置。

但是开发人员是在Web.Config中进行了如下设置:

<system.web>

<httpRuntime maxRequestLength="40960" appRequestQueueLimit="100" useFullyQualifiedRedirectUrl="true" executionTimeout="120" />

</system.web>

这里的maxRequestLength据MSDN介绍:Gets or sets the maximum request size. The maximum request size in kilobytes. The default size is 4096 KB (4 MB).

The MaxRequestLength property specifies the limit for the buffering threshold of the input stream. For example, this limit can be used to prevent denial of service attacks(拒绝服务攻击) that are caused by users who post large files to the server.

The value assigned to this property should be greater or equal to value assigned to the RequestLengthDiskThreshold property.

但是开发人员的这个设置好像是不起作用的。他们在这里,限制最大请求长度为40MB,超时为120s。

下次再看一下具体这个设置是用来做什么的。

-------------------------

现在明白了。这个是用来设置单个请求的最大长度。比如EmailTicket中若设置maxRequestLength为30M,maxAllowedContentLength为40M,

然后在Reply Email时,选择了一个35M的附件,在点击Save as Draft的时候,这个请求的长度大概会有35M,这个已经超过了maxRequestLength。此时请求就会报错了,结果是黄页:

Server Error in '/emailticket' Application.


Maximum request length exceeded.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Web.HttpException: Maximum request length exceeded.

所以,最好是maxRequestLength和maxAllowedContentLength设置为一致的值。

发表在 web server | 标签为 | HTTP Error 404.13 - Not Found & IIS7文件上传的最大大小 maxAllowedContentLength,maxRequestLength已关闭评论

w3c标准height:100% 无作用解决方法

在以前的网页中,table用height:100%是可以整屏的,但在网页头部增加:
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
后就和没有用height:100%一样了,后来发现要给html,body都增加height:100%的属性,这是高度自适应问题的关键所在。

高度自适应的CSS代码:
html,body{
      margin:0px;
    
 height:100%;
}

一个对象高度是否可以使用百分比显示,取决于对象的父级对象,Table在body之中,因此它的父级是body,而浏览器默认状态下,是没有给body一个高度属性的,因此当我们直接设置#left为height:100%;时,不会产生任何效果,而当我们给body设置了100%之后,它的子级对象Table的height:100%;便发生作用了,这便是浏览器解析规则引发的高度自适应问题。而代码中除了给body应用之外,还给
HTML对象也应用相同的样式设计,这样做的好处是使IE与firefox浏览器都能够实现高度自适应。另外,Firefox中的HTML标签不是
100%高度,因此给两个标签都定义为height:100%;以保证两个浏览器下均能够正常显示

 

1.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
的问题。

因为这里声明了你的文档符合html
4.0 标准。而此标准当中, table没有height属性

2.

其实只要把body标签的样式设为100%,这样其他的元素都会以它为标准的了
<body
style="height:100%;margin:0px;">
<table width="100%"
height="100%">

而且去掉文件头上的
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML
4.01
Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

同时如果是表格嵌表格,要每个父表格都要设style="height:100%"

 

<div id="div1" style="Z-INDEX: 1; OVERFLOW: auto; WIDTH: 100%;height:100%"
>不出现滚动条,因为它的父级容易没有设置 height="100%"

发表在 article | 标签为 | w3c标准height:100% 无作用解决方法已关闭评论

MySQL获取某月份的天数

1、last_day(curdate());获取当月最后一天。

2、DAYOFMONTH(last_day(curdate())); 返回date 对应的该月日期。当然这就是当月的天数。

这就出来当月天数了,相当简单。

最初的时候去网上找的下面的内容。虽然逻辑上没错,但是思路有点问题,mysql那么多现成的函数没有用,浪费了。

这是在网上看到的:

MySQL 获取当前月的天数

select curdate();                       --获取当前日期
select DATE_ADD(curdate(),interval -day(curdate())+1 day)   --获取本月第一天
select date_add(curdate()-day(curdate())+1,interval 1 month ) -- 获取下个月的第一天
select DATEDIFF(date_add(curdate()-day(curdate())+1,interval 1 month ),DATE_ADD(curdate(),interval -day(curdate())+1 day)) from dual --获取当前月的天数

发表在 db | 标签为 | MySQL获取某月份的天数已关闭评论

用BIND架设DDNS Server 提供DDNS服务

1.前言
目前动态 DNS 两大主流,一个是 BIND (ISC),另一个就是套接 DB DNS PowerDNS ( mydns)
 
,两种方式各有好坏,主要是因为 BIND 会有一些复杂性,但效果非常好, PowerDNS 则是很简单
,
但相对的它不能承受大量查询,主要原因在于数据库上先天的限制. 本文主要为介绍 BIND 之动态
 
DNS
做法,而这个做法之最重要重点则在于nsupdate 这个指令及
IXFR (incremental zone transfer 
request),
是不同于传统的 AXFR (full zone transfer),IXFR 在做 Zone Transfer (DNS 的同步机制
)
 
,会以差异化的部份进行同步, AXFR 则是以整个 Zone 进行同步.DDNS 主要由 RFC 2136 构成
,
建议若您要对 DDNS 有一定深入的了解,可以阅读这篇 RFC 以了解更多重要的信息

(1034 1035 1995
2136 的基础)

本文适用于对 DNS 巳有一定了解的朋友,若是不甚清楚建议您可先参考 TWNIC 所做的讲义:
http://dns-learning.twnic.net.tw/DNS94/ 

如果你想对 nsupdate + key 的方法有更深入的了解可以参考
http://www.study-area.org/tips/tipsfr1.htm
或参考 isc bind 的文件有最详细的解说
http://www.isc.org/sw/bind/arm93/Bv9ARM.pdf
本文不讨论 view 的情形,若是 view 情形您必需从 view match-client 去更新或是使用不同
key,所以建议您多参考 isb bind 的文件,虽然辛苦些,但数据绝对是最官方最正确的


2.
必要的信息及知识
本文的范例以 Shell Script 做成,重点在于原理,采用什么工具或做法完全视您个人的能力.以下
就一些重点进行说明.

2.1 BIND 动态更新
基本上在 BIND8,BIND9 都是支持 nsupdate ,但这里面要注意的是 BIND8 8.3.X 后才支援 
IXFR,
BIND9 则都支持,所以若您的 Server 8.3.0 前的版本,那就不建议了,更何况这个以

前的版本多多少少都有许多安全性的问题.

2.1.1 nsupdate: 
bind
要开 allow-update 选项,让你的程序可以来执行更新指令,allow-update 选项可以是 IP
 
key,
而本文仅就 IP进行介绍,若用 Key 对有些朋友来说可能会变得稍复杂些了

# named.conf
#
其它略

zone "dyndns.twnic.tw" {
 type master;
 file "dyndns.twnic.tw";
 allow-update {127.0.0.1;};    #
开放 127.0.0.1 进行动态更新 
 allow-transfer { slave_ip;127.0.0.1;};  # slave
主机,可能一部或多部,若无请写
none
};


以上是开放让 127.0.0.1 进行动态更新,动态更新有其指令,详细您可看看 nsupdate man page 
(man nsupdate),
以下仅以最常用的进行说明:

#nsupdate
[root@eai1 dyndns]# nsupdate
> server 127.0.0.1
> zone dyndns.twnic.tw
> update delete user1.dyndns.twnic.tw A 211.72.210.249
> update add user1.dyndns.twnic.tw A 211.72.210.251
ttl 'A': not a valid number  #
这个例子是错误示范,加一笔记录要有 TTL

> update add user1.dyndns.twnic.tw 60 A 211.72.210.251
> show
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:      0
;; flags: ; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; UPDATE SECTION:
user1.dyndns.twnic.tw.  0       NONE    A       211.72.210.249
user1.dyndns.twnic.tw.  60      IN      A       211.72.210.251

> send
> quit


server 
指向某一台 NameServer 进行 update 操作
zone   
修改某个 zone file
update delete 
进行 update delete 动作,这个指令格式是

        update delete FQDN TYPE RDATA,
如果有多笔相同的 A
       
记录或不同的 MX 记录要删除某一笔需将 RDATA 补上
,
       
若没有 RDATA 则表示这个 FQDN 的这个 TYPE 都要删除

        (TYPE
即是 A,MX,PTR,SOA,NS..,RDATA 就是 TYPE
       
接的东西, A RDATA IP MX RDATA
       
先权 FQDN)
update add    
进行记录的增加,操作如同 delete, 但是一定要有

        TTL
,且必需明确写出 RDATA
show   
这只是操作后要显示进行了那些 update 指令

send   
这个代表要把整个 update 指令送给 server,操作 update
       
时数据不是马上送出的,所以 update 可以很多行,最后

        nsupdate
看到 send ,才会将整个所有 update 送出,
       
update 使用 port 53/udp 若送出的数据量
(DNS packet)
       
大于 512 bytes,则会 truncate 而改使用 53/tcp,这是您

       
需要注意的地方,而只要您有 send, SOA 记录的 serial
       
会自动加1,以期让 slave 来进行同步,所以过多的 send

       
能造成过多的 traffic

2.1.2 zone file 及日志文件 
如果您进行了 nsupdate 的操作,则原来 directory 所指的目录将会产生一些日志文件,这个日志文件即为
 
zone_name.jnl (directory
习惯上都设在 /var/named , 您自己必要注意 named 程序要有写入的权限
,
chroot
状况等)

# 显示 dyndns.twnic.tw zone file 内容
[root@eai1 named]# cat /var/named/dyndns.twnic.tw
$TTL 86400      ; 1 day
@         IN SOA  twnic.net.tw. snw.twnic.net.tw. (
                                2006073267 ; serial
                                7200       ; refresh (2 hours)
                                1800       ; retry (30 minutes)
                                2419000    ; expire (3 weeks 6 days 23 hours 56 minutes 40 seconds)
                                300        ; minimum (5 minutes)
                                )
                        NS      ns2.dyndns.twnic.tw.
                        NS      eai1.twnic.tw.
ns2                     A       203.73.24.204
;
如果别人在查询时,我们有这个记录则响应这个记录的 IP,若没有这个记录代表
;
这个网站没有上线,所以此时我们可以建立一笔 wildcard 记录,指向自己的说
;
明网站,以供 user 识别这个网站没有上线,而这笔 wildcard 的记录 TTL 时间
;
不能太长,以免别的 DNS Cache 了这资料
*                 0    A       211.72.210.251

# 目录里的东西
[root@eai1 named]# ls -la /var/named/
总计 128
drwxr-xr-x    2 named    named        4096  7
27 09:25 .
drwxr-xr-x   20 root     root         4096  3
13 16:50 ..
-rw-r--r--    1 named    named         451  7
27 09:25 dyndns.twnic.tw
-rw-r--r--    1 named    named      104177  7
27 10:01 dyndns.twnic.tw.jnl
-rw-r--r--    1 named    named         195  7
  4  2001 localhost.zone
-rw-r--r--    1 named    named        2851 10
17  2003 named.ca

我们可以看到这个 .jnl 的产生,这个 .jnl 档是不能随便删除,因为它等于是 dyndns.twnic.tw 的补
充数据,而这些补充资料在 DNS reload/restart , named 还会在把它读进来,所以动态更新后的数据,
并不会随着 dns 重启后而消失,如果你想让现在整个 zone 文件出现所有的记录,那可以 rndc stop 来停止
 
dns,
此时 named 会把 .jnl数据写入原来的 zone file,不过这种方式一般来说较不建议,因为我们的
zone
 file
只要存一个样版 (template),其它的东西都是临时性的. 而若你想知道现在整个 zone 的内容,在可

以做 zone transfer 的主机上(如上例为 slave_ip 127.0.0.1), dig 指令来执行 axfr:

[root@eai1 dyndns]# dig @127.0.0.1 dyndns.twnic.tw axfr

; <<>> DiG 9.3.0 <<>> @127.0.0.1 dyndns.twnic.tw axfr
;; global options:  printcmd
dyndns.twnic.tw.        86400   IN      SOA     twnic.net.tw. snw.twnic.net.tw. 2006073528 7200 1800 2419000 300
dyndns.twnic.tw.        86400   IN      NS      ns2.dyndns.twnic.tw.
dyndns.twnic.tw.        86400   IN      NS      eai1.twnic.tw.
*.dyndns.twnic.tw.      0      IN      A       211.72.210.251
ns2.dyndns.twnic.tw.    86400   IN      A       203.73.24.204
user1.dyndns.twnic.tw.  60      IN      A       211.72.210.248
user1.dyndns.twnic.tw.  60      IN      MX      10 user1.dyndns.twnic.tw.
#
以下略

...

2.设定 NameServer 仅进行差异化的同步 
Master/Slave
要进行 zone file 的同步, ddns server 若只有一部是可以不用考虑这些问题的,但是若有两

部以上的 DNS Server, 就需要考虑到同步的进行方式, zone file 的总数据量小,采用什么同步方式是无所
谓的,但若数据量多,或是经常处在变动状况,那差异化的同步就会显得很重要,因为它可以让所有的 DNS 在短时
间内全部同步完成,BIND 支持 IXFR ,其预设即是采用 IXFR, 若没有 IXFR (update) ,则采用 AXFR,所以不
需要对 IXFR 进行额外设定,但为使大家了解其参数,本处还是举例来进行说明,好让大家能够更了解


# master DNS's named.conf
key "rndc-key" {
        algorithm hmac-md5;
        secret "HpXtFRFdLaRPFjpZokIwusyezyyRNjxhcafCfmktWNyGkDFzHAXlpTZQtVLc";
};

controls {
        inet 127.0.0.1 port 953
                allow { 127.0.0.1; } keys { "rndc-key"; };
};

options {
        directory "/var/named";
        pid-file "/var/run/named/named.pid";
        allow-transfer { none; };
        provide-ixfr yes;   #
提供 slave 主机以 IXFR 同步
,default yes
        request-ixfr yes;   # slave
IXFR master 进行同步
,default yes
 recursion no;       #
不允许递归查询

};
zone "0.0.127.in-addr.arpa" {
        type master;
        file "named.local";
};
zone "." {
        type hint;
        file "named.ca";
};
zone "dyndns.twnic.tw" {
        type master;
        file "dyndns.twnic.tw";
        max-journal-size 500k;                      #
设定日志文件大小
        allow-transfer { 203.73.24.204;127.0.0.1;}; #
可做 ixfr/axfr 的来源 IP,必需写上 slave,
                                                    # 127.0.0.1
是方使我们自己查看 zone file 现况

        also-notify {203.73.24.205;211.72.210.251}; #
额外的同步主机,这可能是 hot site 备份主机
        allow-update { 127.0.0.1;};                 #
允许动态更新的来源
};


上述的东西相信只要对 BIND DNS 有一定了解的朋友应该都是没有问题的,较不常出现的项目我都加上了的批注以利
大家了解, slave 的设法都同于 master, 只有在 zone 的部份稍有不同:

# slave DNS's named.conf
#
其它设定皆同上,只有 zone ...稍有不同,同于一般的 slave zone,不需要再开
allow-update (default none)
zone "dyndns.twnic.tw" {
        type slave;
        masters {211.72.210.249;};
        file "dyndns.twnic.tw";
        allow-transfer { none;};
};


所以从上述我们可以知道 DDNS for Master/Slave 您只要对 master 进行 update,每次的 update 送出 (send) 
会使该zone 的序号加一,只要 zone 有更新 , dns 会送出 notify 讯息给所有的 NS 主机(NS 记录上所列的名称

服务器),及可能的 also-notify 对象,使 slave 主机知道要进行同步,同步时优先采用 IXFR, master 不支持 
IXFR
则改使用 AXFR,以达到即使更新,及时同步的效果


此外,有些做 DDNS 的公司可能对 IXFR 不了解,而是把所有的 zone type 都设成了 MASTER,然后对这些 NameServer
进行 nsupdate , 这种做法也是可以的,不过中间若漏了一步或那一台少做了一件事,那两边的资料就会不一致,导致

可能同一个名称会有不同的解析结果 (例如 gnway.net 做法)

--------------------------------------------------------------------------------
 abel
回复于:2006-07-28 14:52:21

3. DDNS 的前端及后台控制范例 
说是范例主要是让大家参考原理,并没有必要一定都用我的方式,只要前面讲的东西您可以了解,程控的部份

仅是末节,以下仅列出我所用的方式供大家参考

3.1 MYSQL table
主要由三个表构成,分别为 RR (Resource Record), RR_LOG (旧资料,建议您依状况适当保存),USER (user 认证)

CREATE TABLE RR (
  SN int(20) NOT NULL auto_increment,
  USERNAME varchar(64) NOT NULL default '',
  FQDN varchar(64) NOT NULL default '',
  TTL int(5) NOT NULL default '60',
  TYPE varchar(10) NOT NULL default '',
  RDATA varchar(64) NOT NULL default '',
  CREATE_TIME timestamp(14) NOT NULL,
  PRIMARY KEY  (SN),
  KEY USERNAME (USERNAME),
  KEY FQDN (FQDN),
  KEY TTL (TTL),
  KEY TYPE (TYPE),
  KEY CREATE_TIME (CREATE_TIME)
) TYPE=MyISAM;

--
-- Table structure for table 'RR_LOG'
--

CREATE TABLE RR_LOG (
  SN int(20) NOT NULL default '0',
  USERNAME varchar(64) NOT NULL default '',
  FQDN varchar(64) NOT NULL default '',
  TTL int(5) NOT NULL default '60',
  TYPE varchar(10) NOT NULL default '',
  RDATA varchar(64) NOT NULL default '',
  CREATE_TIME varchar(14) default NULL,
  PRIMARY KEY  (SN),
  KEY USERNAME (USERNAME),
  KEY FQDN (FQDN),
  KEY CREATE_TIME (CREATE_TIME)
) TYPE=MyISAM;

--
-- Table structure for table 'USER'
--

CREATE TABLE USER (
  SN int(20) NOT NULL auto_increment,
  USERNAME varchar(64) NOT NULL default '',
  PASSWD varchar(64) NOT NULL default '',
  EMAIL varchar(64) NOT NULL default '',
  MEMO varchar(255) NOT NULL default '',
  PRIMARY KEY  (SN),
  UNIQUE KEY USERNAME (USERNAME)
) TYPE=MyISAM;


3.2 dyndns.cfg
设定档 
这个设定文件主要为了给 CGI 程序及产生 nsupdate 的程序 (dyndns-cron.sh) 所使用,透过 eval 方式来执行
,
以取得共同的变量

# mysql host/db/user/password
DBHOST=localhost
DBNAME=dyndns
DBUSER=UserName
DBPASS=Your_Passwd
MYSQL="mysql $DBNAME -h $DBHOST -u $DBUSER -p$DBPASS"

# dyndns domain
DOMAIN=dyndns.twnic.tw

# Master IP
DYNDNS_MASTER=127.0.0.1

# nsupdate command file
CMD_FILE=/tmp/nsupdate.cmd

# update freqency
UPD_FREQ=15

# RR valid time (seconds),default 20 mins
RR_ALIVE=1200


3.3 dyndns.cgi CGI
程序 
这个 CGI 主要用于接收 USER 端来的信息,验证通过后即为把 USERNAME.DOMAIN 数据,A/MX 及对应 IP 存入

 Table RR
,此外这个 CGI shell script 做成,可以于多数人的环境执行 (chmod 755 及目录的 CGI
行权限 ExecCGI 莫忘)

#!/bin/sh
echo -ne "Content-Type: text/html\n\n"

if [ -n "$QUERY_STRING" ];then
#
取得 QUERY_STRING,以下这个作法是危险的,因为没有检查数据的正确性就
eval
#
我的用意只在于说明作法

        eval `echo "$QUERY_STRING" | sed "s/&/;/g"`
#
读取设定文件,这个路径您需要自行调整
        eval `cat /home/abelyang/dyndns/dyndns.cfg `
        sql0="select 1 from USER where USERNAME='$LOGIN' and PASSWD='$PASSWD'"
        res=`echo $sql0 | $MYSQL `
#
如果 USER 密码正确, ${#res} 应为2,不对则为 0
        if [ ${#res} -lt 1 ];then
                echo "Login Failure"
        else
#
取得 IP, 需判断有 Proxy 存在,但是不考虑 Proxy 后是 NAT 情形

                IP=${HTTP_X_FORWARDED_FOR:-$REMOTE_ADDR}
                FQDN="$LOGIN.$DOMAIN"
#
删除上一次的登入
                sql1="delete from RR where USERNAME='$LOGIN'"
#
预设的动态更新项目为 A/MX
                sql2="insert into RR(USERNAME,FQDN,TYPE,RDATA) values('$LOGIN','$FQDN','A','$IP')"
                sql3="insert into RR(USERNAME,FQDN,TYPE,RDATA) values('$LOGIN','$FQDN','MX','10 $FQDN')"
                echo $sql1 | $MYSQL
                echo $sql2 | $MYSQL
                echo $sql3 | $MYSQL
                echo $LOGIN login success @$IP
        fi
else
#
以下只是网页的部份,我没有做 DDNS 申请,这个部份我想只要懂网页的朋友应该都会才是

        cat <<EOF
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=big5" />
<link rel="stylesheet" href="./style1.css">
</head>
<body>
<BR><BR><center>
<form>
<h3>Abel Dyndns Demo </h3>
Login:<input type=text name=LOGIN ><BR>
Passwd:<input type=password name=PASSWD><BR>
<input type=submit values="Start DynDNS">
</form>
<BR></center>
</body>
</html>

EOF


fi

3.4 dyndns-cron.sh 定时产生 nsupdate 
这只程序主要进行读取 Table RR , 并产生 nsupdate 所需要的指令格式后执行 nsupdate, 程序预设

15秒执行一次(参数如上 dyndns.cfg 中的 UPD_FREQ 更新频率),您可以拿掉 while [ 1 ] 的循环,
改用 crontab 方式来跑,不过这样就较不容易控制一分钟以内的更新频率了,最后,这个程序会把
SOA 
的序号改成更新时间,这个时间是 UTC 的秒数(意即 1970/1/1 至今秒数, date +%s 可得), SOA

序号就可以知道最后的 update 时间,这个原理和 .com verisign 或是 dyndns 中的 dyndns.org/
noip.com
是相同的.

另外,根据 RR_VALID 参数, USER 的登录时间 小于 现在时间-RR_VALID (秒数),则该 Record 视同
离线,所以我们需要进行 delete 动作


#!/bin/sh

while [ 1 ]
do
#
您必需调整路径,放在 while loop 里是要让修改了设定档即可生效,若不要可放在 while 之外

        eval `cat /home/abelyang/dyndns/dyndns.cfg`
        cat <<EOF > $CMD_FILE
server $DYNDNS_MASTER
zone $DOMAIN
EOF

# 取得最后一次的更新时间, 多减一秒是为了预防程序的 delay
        last=`date -d "-$UPD_FREQ seconds -3 seconds" "+%Y%m%d%H%M%S"`
        now=`date "+%Y%m%d%H%M%S"`

# 取得这段时间内有上来更新的 USER,这个部份不检查 IP 不变动情形
#
主要因为 nsupdate 巳执行很快,而且 named 它自己会检查重复更新的东西
        echo "select FQDN,TTL,TYPE,RDATA from RR where CREATE_TIME between $last and $now" | $MYSQL| grep -v 'RDATA' | while read FQDN TTL TYPE RDATA RDATA2
        do

# 组出更新指令,主要为一个删除,一个增加
                echo "update delete $FQDN $TYPE $RDATA $RDATA2" >>$CMD_FILE
                echo "update add $FQDN $TTL $TYPE $RDATA $RDATA2" >>$CMD_FILE
        done

# 超过 RR_ALIVE (20分钟) 未有 login 数据则清除 DNS 记录
        last=`date -d "-$RR_ALIVE seconds" "+%Y%m%d%H%M%S"`
#
备份旧的数据,并清除过时数据 (看你自己要不要备份了)
#       echo "insert into RR_LOG select * from RR where CREATE_TIME<$last"|$MYSQL
#       echo "delete from RR where CREATE_TIME < $last" |$MYSQL

# 取得过期 (RR_ALIVE) 而未登录的列表进行删除动作,因为我们用了 wildcard (*),所以若别人连时
#
将会被指到 wildcard 所指的 IP ,而您可这个 Web Server 上做一些文章,例如 Offline 说明等
        echo "select USERNAME,FQDN,TYPE,RDATA from RR  where CREATE_TIME - $last < 0 order by USERNAME" | $MYSQL | grep -v 'USERNAME' | while read USERNAME FQDN TYPE RDATA RDATA2
        do
                echo "; delete $FQDN $TYPE $RDATA $RDATA2" >>$CMD_FILE
                echo "update delete $FQDN $TYPE $RDATA $RDATA2" >>$CMD_FILE
        done

# 自定更新 SOA, 主要是为了让序号字段为现在时间 (UTC)
        echo "update delete $DOMAIN SOA" >>$CMD_FILE
        echo "update add $DOMAIN 600 SOA ns1.dyndns.twnic.tw abelyang.eai1.twnic.tw $(date +%s) 900 60 604800 60" >>$CMD_FILE
        echo "send" >>$CMD_FILE
#
执行 nsupdate 指令

        nsupdate $CMD_FILE
#       echo "process ok"
        sleep $UPD_FREQ
done

3.5 登入及更新方法
所有的东西都准备好了后,我们就可以测试:

wget "http://eai1.twnic.tw/dyndns.cgi?LOGIN=abelyang&PASSWD=abelyang-dyndns" -O /tmp/dyndns-login-status 2>/dev/null


在最多等待15(我的默认值)的情况下,就可以更新到 DNS 中了

3.6 其它数据 
其它数据如 named.conf , dyndns.twnic.tw zone file 您都可以在前面的说明里找到,我于下面
link
放了一份所有的数据供大家参考,较不用费事 copy & paste ,但不保证下面 link 永远有效 (其中的
 
.tgz
即有所有档案的
tarball)
http://eai1.twnic.tw/example/


4. DDNS
再探讨 
如前言所言, DDNS 可以使用数据库来用 (意即我的范例中可以少掉 dyndns-cron.sh 那只),不过数据库

因其先天的状况,更据我的测试(PowerDNS), 5 万资 Record 的情况下,只能到达每秒 1000 次的查询,
而且此时尚不考虑同时有 update/delete/insert 等情形,主要因为受限于先天 DB select 速度所致

,
当然您可以透过微调或细部处理让这个数字变成1500 2000, 但都永不如 BIND 随便都可以透过每秒 
6000
次查询,当然用 DB 直接来做一定是可以且更简单的,不过安全性及抗压性 PowerDNS 是随时都会有

当掉的风险,至于用 BIND 倒是没有看过,主要是因为这种 Server 肯定是不递归(recursion no). 所以
著名的 DDNS 厂商都是用 BIND 而不用 DB 方式,因其抗压性不足而致风险过高.

此外,若我们看 dyndns.org/noip.com 的做法,可以知道他们也是用 BIND 来做,你可以查询其 SOA 的序
号即可以知道他每60秒更新一次,若是使用 DB 来做是没有必要顾虑序号问题的 (DB DB 同步方法, 
SOA
序号无关),此外您更可以查看 .com Verisign,他们的做法也是像 BIND 一样,而其以每15秒更新

频率在进行,所以若您使用 .com 的域名,变更DNS 大概只要15秒就可以同步到所有的 .com NameServer, 
而不是过去的2 (因为过去是 AXFR,现在是 IXFR),虽然Verigisn 仍不降低 NS 记录的 TTL (二天
),
但至少不会发生像过去最多会4 .com DNS 数据 Cache 才会过期的情况 (二天的更新频率+二天的

快取时间)


#
检查 .com NameServer (d.gtld-servers.net) SOA 信息来验证
[root@eai1 example]# for i in `seq 1 1000`;do dig +short @d.gtld-servers.net com soa;sleep 1;done
a.gtld-servers.net. nstld.verisign-grs.com. 1153990708 1800 900 604800 900
a.gtld-servers.net. nstld.verisign-grs.com. 1153990708 1800 900 604800 900
a.gtld-servers.net. nstld.verisign-grs.com. 1153990708 1800 900 604800 900
a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900 #
这里变更了, serial 即时间
a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
a.gtld-servers.net. nstld.verisign-grs.com. 1153990738 1800 900 604800 900 #
变更序号
a.gtld-servers.net. nstld.verisign-grs.com. 1153990738 1800 900 604800 900
a.gtld-servers.net. nstld.verisign-grs.com. 1153990738 1800 900 604800 900

5. 结语 
我所写的 script 都是以简单的角度来出发,以供大家参考,至于用户及域名管理这个有待想要用的人自行

开发, shell script 有利于多数人阅读及了解原理,细节的东西唯有您自己做了后才更能体会.
对多数的公司来说使用 DDNS 是没有意义的,除了 Registy (.com/cn/tw/jp/hk...),或是以 DDNS 做为营

运的公司, DDNS其实是不难的,但是网络上较缺乏这方面的介绍文章,所以在此为大家介绍一下这些东西
的细节, 以利想要研究的朋友能初窥门径. 有任何意见都非常欢迎大家多多交流


:
此外,有些做 DDNS 的公司可能对 IXFR 不了解,而是把所有的 zone type 都设成了 MASTER,然后对这些
 
NameServer
进行 nsupdate , 这种做法也是可以的,不过中间若漏了一步或那一台少做了一件事,那两边

的数据就会不一致,导致可能同一个名称会有不同的解析结果 (例如 gnway.net 做法,我猜测),而像 dyndns.org
/noip.com
和花生壳(vicp.net,oray.net) 等的做法是一样的(也就是和本文所提的做法一样). 而有些

公司则使用 PowerDNS/Mydnl..等套接 DB DNS ,虽然可用,而且方式更简单,但是这些 DDNS 服务肯定
无法负荷大量的查询,因为每次的 dns 查询会在其内产生 N 次的 Select 指令,数据库处理 select
速度肯定是比不上 dns flooding 的速度

发表在 article | 标签为 , | 用BIND架设DDNS Server 提供DDNS服务已关闭评论

备份mysql数据

其实你的这个问题是mysql中的一个核心问题,既mysql数据的备份和恢复
你可以使用三种方式
1.使用sql语句导入导出
2.使用mysqldump 和mysqlimport 工具
3.直接copy 数据文件 既冷备份
你说说的详细,就给积分,那我就说详细些

一.使用sql语句完成mysql的备份和恢复

你可以使用SELECT INTO OUTFILE语句备份数据,并用LOAD DATA INFILE语句恢复数据。这种方法只能导出数

据的内容,不包括表的结构,如果表的结构文件损坏,你必须要先恢复原来的表的结构。
语法:
SELECT * INTO {OUTFILE | DUMPFILE} 'file_name' FROM tbl_name
LOAD DATA [LOW_PRIORITY] [LOCAL] INFILE 'file_name.txt' [REPLACE | IGNORE]
INTO TABLE tbl_name
SELECT ... INTO OUTFILE 'file_name'格式的SELECT语句将选择的行写入一个文件。文件在服务器主机上被创建,并且不能是已经存在的(不管别的,这可阻止数据库表和文件例如“/etc/passwd”被破坏)。SELECT ... INTO OUTFILE是LOAD DATA INFILE逆操作。
LOAD DATA INFILE语句从一个文本文件中以很高的速度读入一个表中。如果指定LOCAL关键词,从客户主机读文件。如果LOCAL没指定,文件必须位于服务器上。(LOCAL在MySQL3.22.6或以后版本中可用。)
为了安全原因,当读取位于服务器上的文本文件时,文件必须处于数据库目录或可被所有人读取。另外,为了对服务器上文件使用LOAD DATA INFILE,在服务器主机上你必须有file的权限。使用这种SELECT INTO OUTFILE语句,在服务器主机上你必须有FILE权限。
为了避免重复记录,在表中你需要一个PRIMARY KEY或UNIQUE索引。当在唯一索引值上一个新记录与一个老记录重复时,REPLACE关键词使得老记录用一个新记录替代。如果你指定IGNORE,跳过有唯一索引的现有行的重复行的输入。如果你不指定任何一个选项,当找到重复索引值时,出现一个错误,并且文本文件的余下部分被忽略时。
如果你指定关键词LOW_PRIORITY,LOAD DATA语句的执行被推迟到没有其他客户读取表后。
使用LOCAL将比让服务器直接存取文件慢些,因为文件的内容必须从客户主机传送到服务器主机。在另一方面,你不需要file权限装载本地文件。如果你使用LOCAL关键词从一个本地文件装载数据,服务器没有办法在操作的当中停止文件的传输,因此缺省的行为好像IGNORE被指定一样。
当在服务器主机上寻找文件时,服务器使用下列规则:
 如果给出一个绝对路径名,服务器使用该路径名。
 如果给出一个有一个或多个前置部件的相对路径名,服务器相对服务器的数据目录搜索文件。
 如果给出一个没有前置部件的一个文件名,服务器在当前数据库的数据库目录寻找文件。
假定表tbl_name具有一个PRIMARY KEY或UNIQUE索引,备份一个数据表的过程如下:
1、锁定数据表,避免在备份过程中,表被更新
mysql>LOCK TABLES READ tbl_name;
关于表的锁定的详细信息,将在下一章介绍。
2、导出数据
mysql>SELECT * INTO OUTFILE ‘tbl_name.bak’ FROM tbl_name;
3、解锁表
mysql>UNLOCK TABLES;
相应的恢复备份的数据的过程如下:
1、为表增加一个写锁定:
mysql>LOCK TABLES tbl_name WRITE;
2、恢复数据
mysql>LOAD DATA INFILE ‘tbl_name.bak’
  ->REPLACE INTO TABLE tbl_name;
如果,你指定一个LOW_PRIORITY关键字,就不必如上要对表锁定,因为数据的导入将被推迟到没有客户读表为止:
mysql>LOAD DATA  LOW_PRIORITY  INFILE ‘tbl_name’
  ->REPLACE INTO TABLE tbl_name;
3、解锁表
mysql->UNLOCAK TABLES;
5.3.2使用mysqlimport恢复数据
如果你仅仅恢复数据,那么完全没有必要在客户机中执行SQL语句,因为你可以简单的使用mysqlimport程序,它完全是与LOAD DATA 语句对应的,由发送一个LOAD DATA INFILE命令到服务器来运作。执行命令mysqlimport --help,仔细查看输出,你可以从这里得到帮助。
shell> mysqlimport [options] db_name filename ...
对于在命令行上命名的每个文本文件,mysqlimport剥去文件名的扩展名并且使用它决定哪个表导入文件的内容。例如,名为“patient.txt”、“patient.text”和“patient”将全部被导入名为patient的一个表中。
常用的选项为:
-C, --compress 如果客户和服务器均支持压缩,压缩两者之间的所有信息。
-d, --delete 在导入文本文件前倒空表格。
l, --lock-tables 在处理任何文本文件前为写入所定所有的表。这保证所有的表在服务器上被同步。
--low-priority,--local,--replace,--ignore分别对应LOAD DATA语句的LOW_PRIORITY,LOCAL,REPLACE,IGNORE关键字。
例如恢复数据库db1中表tbl1的数据,保存数据的文件为tbl1.bak,假定你在服务器主机上:
shell>mysqlimport --lock-tables --replace db1 tbl1.bak
这样在恢复数据之前现对表锁定,也可以利用--low-priority选项:
shell>mysqlimport --low-priority --replace db1 tbl1.bak
如果你为远程的服务器恢复数据,还可以这样:
shell>mysqlimport -C --lock-tables --replace db1 tbl1.bak
当然,解压缩要消耗CPU时间。
象其它客户机一样,你可能需要提供-u,-p选项以通过身分验证,也可以在选项文件my.cnf中存储这些参数,具体方法和其它客户机一样,这里就不详述了。

二、使用mysqldump备份数据
同mysqlimport一样,也存在一个工具mysqldump备份数据,但是它比SQL语句多做的工作是可以在导出的文件中包括SQL语句,因此可以备份数据库表的结构,而且可以备份一个数据库,甚至整个数据库系统。
mysqldump [OPTIONS] database [tables]
mysqldump [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]
mysqldump [OPTIONS] --all-databases [OPTIONS]
如果你不给定任何表,整个数据库将被倾倒。
通过执行mysqldump --help,你能得到你mysqldump的版本支持的选项表。
1、备份数据库的方法
例如,假定你在服务器主机上备份数据库db_name
shell> mydqldump db_name
当然,由于mysqldump缺省时把输出定位到标准输出,你需要重定向标准输出。例如,把数据库备份到bd_name.bak中:
shell> mydqldump db_name>db_name.bak
你可以备份多个数据库,注意这种方法将不能指定数据表:
shell> mydqldump --databases db1 db1>db.bak
你也可以备份整个数据库系统的拷贝,不过对于一个庞大的系统,这样做没有什么实际的价值:
shell> mydqldump --all-databases>db.bak
虽然用mysqldump导出表的结构很有用,但是恢复大量数据时,众多SQL语句使恢复的效率降低。你可以通过使用--tab选项,分开数据和创建表的SQL语句。
-T,--tab= 在选项指定的目录里,创建用制表符(tab)分隔列值的数据文件和包含创建表结构的SQL语句的文件,分别用扩展名.txt和.sql表示。该选项不能与--databases或--all-databases同时使用,并且mysqldump必须运行在服务器主机上。
例如,假设数据库db包括表tbl1,tbl2,你准备备份它们到/var/mysqldb
shell>mysqldump --tab=/var/mysqldb/  db
其效果是在目录/var/mysqldb中生成4个文件,分别是tbl1.txt、tbl1.sql、tbl2.txt和tbl2.sql。
2、mysqldump实用程序时的身份验证的问题
同其他客户机一样,你也必须提供一个MySQL数据库帐号用来导出数据库,如果你不是使用匿名用户的话,可能需要手工提供参数或者使用选项文件:
如果这样:
shell>mysql -u root –pmypass db_name>db_name.sql
或者这样在选项文件中提供参数:
[mysqldump]
user=root
password=mypass
然后执行
shell>mysqldump db_name>db_name.sql
那么一切顺利,不会有任何问题,但要注意命令历史会泄漏密码,或者不能让任何除你之外的用户能够访问选项文件,由于数据库服务器也需要这个选项文件时,选项文件只能被启动服务器的用户(如,mysql)拥有和访问,以免泄密。在Unix下你还有一个解决办法,可以在自己的用户目录中提供个人选项文件(~/.my.cnf),例如,/home/some_user/.my.cnf,然后把上面的内容加入文件中,注意防止泄密。在NT系统中,你可以简单的让c:\my.cnf能被指定的用户访问。
你可能要问,为什么这么麻烦呢,例如,这样使用命令行:
shell>mysql -u root –p db_name>db_name.sql
或者在选项文件中加入
[mysqldump]
user=root
password
然后执行命令行:
shell>mysql db_name>db_name.sql
你发现了什么?往常熟悉的Enter password:提示并没有出现,因为标准输出被重定向到文件db_name.sql中了,所以看不到往常的提示符,程序在等待你输入密码。在重定向的情况下,再使用交互模式,就会有问题。在上面的情况下,你还可以直接输入密码。然后在文件db_name.sql文件的第一行看到:
Enter password:#……..
你可能说问题不大,但是mysqldump之所以把结果输出到标准输出,是为了重定向到其它程序的标准输入,这样有利于编写脚本。例如:
用来自于一个数据库的信息充实另外一个MySQL数据库也是有用的:
shell>mysqldump --opt database | mysql --host=remote-host -C database
如果mysqldump仍运行在提示输入密码的交互模式下,该命令不会成功,但是如果mysql是否运行在提示输入密码的交互模式下,都是可以的。
 如果在选项文件中的[client]或者[mysqldump]任何一段中指定了password选项,且不提供密码,即使,在另一段中有提供密码的选项password=mypass,例如
[client]
user=root
password
[mysqldump]
user=admin
password=mypass
那么mysqldump一定要你输入admin用户的密码:
mysql>mysqldump db_name
即使是这样使用命令行:
mysql>mysqldump –u root –ppass1 db
也是这样,不过要如果-u指定的用户的密码。
其它使用选项文件的客户程序也是这样
3、有关生成SQL语句的优化控制
--add-locks  生成的SQL 语句中,在每个表数据恢复之前增加LOCK TABLES并且之后UNLOCK TABLE。(为了使得更快地插入到MySQL)。
--add-drop-table 生成的SQL 语句中,在每个create语句之前增加一个drop table。
-e, --extended-insert  使用全新多行INSERT语法。(给出更紧缩并且更快的插入语句)
下面两个选项能够加快备份表的速度:
-l, --lock-tables. 为开始导出数据前,读锁定所有涉及的表。
-q, --quick 不缓冲查询,直接倾倒至stdout。
理论上,备份时你应该指定上诉所有选项。这样会使命令行过于复杂,作为代替,你可以简单的指定一个--opt选项,它会使上述所有选项有效。
例如,你将导出一个很大的数据库:
shell> mysqldump --opt db_name > db_name.txt
当然,使用--tab选项时,由于不生成恢复数据的SQL语句,使用--opt时,只会加快数据导出。
4、恢复mysqldump备份的数据
由于备份文件是SQL语句的集合,所以需要在批处理模式下使用客户机
 如果你使用mysqldump备份单个数据库或表,即:
shell>mysqldump --opt db_name > db_name.sql
由于db_name.sql中不包括创建数据库或者选取数据库的语句,你需要指定数据库
shell>mysql db2 < db_name.sql
 如果,你使用--databases或者--all-databases选项,由于导出文件中已经包含创建和选用数据库的语句,可以直接使用,不比指定数据库,例如:
shell>mysqldump --databases db_name > db_name.sql
shell>mysql <db_name.sql
 如果你使用--tab选项备份数据,数据恢复可能效率会高些
例如,备份数据库db_name后在恢复:
shell>mysqldump --tab=/path/to/dir --opt test
如果要恢复表的结构,可以这样:
shell>mysql < /path/to/dir/tbl1.sql

如果要恢复数据,可以这样
shell>mysqlimport -l db /path/to/dir/tbl1.txt

如果是在Unix平台下使用(推荐),就更方便了:
shell>ls -l *.sql | mysql db
shell>mysqlimport --lock-tables db /path/to/dir/*.txt

三 .用直接拷贝的方法备份恢复
根据本章前两节的介绍,由于MySQL的数据库和表是直接通过目录和表文件实现的,因此直接复制文件来备份数据库数据,对MySQL来说特别方便。而且自MySQL 3.23起MyISAM表成为缺省的表的类型,这种表可以为在不同的硬件体系中共享数据提供了保证。
使用直接拷贝的方法备份时,尤其要注意表没有被使用,你应该首先对表进行读锁定。
备份一个表,需要三个文件:
对于MyISAM表:
tbl_name.frm  表的描述文件
tbl_name.MYD 表的数据文件
tbl_name.MYI  表的索引文件
对于ISAM表:
tbl_name.frm  表的描述文件
tbl_name.ISD 表的数据文件
tbl_name.ISM  表的索引文件
你直接拷贝文件从一个数据库服务器到另一个服务器,对于MyISAM表,你可以从运行在不同硬件系统的服务器之间复制文件

像你这个问题,可以把远程机器的mysql数据目录ftp下载到你本地的mysql目录下,重启mysql就可以了

发表在 db | 标签为 | 备份mysql数据已关闭评论

删除MYSQl BIN-LOG 日志

1.查找当前有哪些二进制日志文件:
mysql> show binary
logs;

+------------------+-----------+
| Log_name | File_size
|

+------------------+-----------+
| mysql-bin.000001 | 1357315 |
|
mysql-bin.000002 | 117 |

| mysql-bin.000003 | 404002 |
|
mysql-bin.000004 | 2050722 |

| mysql-bin.000005 | 139103 |
|
mysql-bin.000006 | 46702 |

| mysql-bin.000007 | 117 |
| mysql-bin.000008
| 98 |

| mysql-bin.000009 | 117 |
| mysql-bin.000010 | 1254 |
|
mysql-bin.000011 | 117 |

| mysql-bin.000012 | 29394942 |
|
mysql-bin.000013 | 422100 |

| mysql-bin.000014 | 117 |
|
mysql-bin.000015 | 117 |

| mysql-bin.000016 | 98 |
| mysql-bin.000017 |
117 |

| mysql-bin.000018 | 117 |
| mysql-bin.000019 | 285300 |
|
mysql-bin.000020 | 181229 |

| mysql-bin.000021 | 98 |
+------------------+-----------+
21 rows in set (0.03
sec)


2.删除bin-log(删除mysql-bin.000018之前的所有二进制日志文件)
mysql> purge binary
logs to 'mysql-bin.000018';

Query OK, 0 rows affected (0.08 sec)

mysql>
show binary logs;

+------------------+-----------+
| Log_name | File_size
|

+------------------+-----------+
| mysql-bin.000018 | 117 |
|
mysql-bin.000019 | 285300 |

| mysql-bin.000020 | 181229 |
|
mysql-bin.000021 | 98 |

+------------------+-----------+
4 rows in set
(0.00 sec)

mysql> show binlog
events;

+------------------+-----+-------------+-----------+-------------+---------------------------------------+
|
Log_name | Pos | Event_type | Server_id | End_log_pos | Info
|

+------------------+-----+-------------+-----------+-------------+---------------------------------------+
|
mysql-bin.000018 | 4 | Format_desc | 1 | 98 | Server ver: 5.0.45-log, Binlog
ver: 4 |

| mysql-bin.000018 | 98 | Stop | 1 | 117 | |
+------------------+-----+-------------+-----------+-------------+---------------------------------------+
2
rows in set (0.01 sec)

删除说明:
如果没有主从复制,可以通过reset master的方式,重置数据库日志,清除之前的日志文件:

reset master;

但是如果存在复制关系,应当通过PURGE的方式来清理bin日志,语法如下:

PURGE {MASTER | BINARY} LOGS TO 'log_name'
PURGE {MASTER | BINARY} LOGS BEFORE 'date'

用于删除列于在指定的日志或日期之前的日志索引中的所有二进制日志。这些日志也会从记录在日志索引文件中的清单中被删除,这样被给定的日志成为第一个。

例如:

PURGE MASTER LOGS TO 'mysql-bin.010';
PURGE MASTER LOGS BEFORE '2014-08-30 00:00:00';  //清理该日期之前的数据
PURGE MASTER LOGS BEFORE DATE_SUB( NOW( ), INTERVAL 3 DAY);  //清除3天前的

发表在 db | 标签为 | 删除MYSQl BIN-LOG 日志已关闭评论

bind dlz 安装配置

bind:

bind+SDB+mysql
bind+DLZ+mysql
bind+nsupdate + IXFR

______________________________________

read:

http://bind-dlz.sourceforge.net/mysql_driver.html

 

-------------------------------


cd /usr/local/src

wget ftp://ftp.bind.com/pub/bind9/9.5.0/bind-9.5.0.tar.gz
tar zxvf bind-9.5.0.tar.gz
cd bind-9.5.0
./configure –with-dlz-mysql –enable-threads –prefix=/usr/local/bind
make
make install
cd /usr/local/bind/etc/
../sbin/rndc-confgen >rndc.conf
tail -n10 rndc.conf | head -n9 | sed -e s/#\//g >named.conf
vi localhost.zone
ttl 86400
@ IN SOA localhost. root.localhost. (
1997022700 ; Serial
28800 ; Refresh
14400 ; Retry
3600000 ; Expire
86400 ) ; Minimum
IN NS localhost.
1 IN PTR localhost.
dig > named.root
vi named.conf
在最后加上
dlz “Mysql zone” {
database “mysql
{host=127.0.0.1 dbname=dns ssl=false port=3306 user=root pass= }
{select zone from dns_records where zone = ‘%zone%’ limit 1}
{select ttl, type, mx_priority, case when lower(type)=’txt’ then concat(’\”‘, data, ‘\”‘) when lower(type) = ’soa’ then concat_ws(’ ‘, data, resp_person, serial, refresh, retry, expire, minimum) else data end as mydata from dns_records where zone = ‘%zone%’ and host = ‘%record%’}
{}
{select ttl, type, host, mx_priority, case when lower(type)=’txt’ then concat(’\”‘, data, ‘\”‘) else data end as mydata, resp_person, serial, refresh, retry, expire, minimum from dns_records where zone = ‘%zone%’}
{select zone from xfr_table where zone = ‘%zone%’ and client = ‘%client%’ limit 1}
{update data_count set count = count + 1 where zone =’%zone%’}”;
};

安装Mysql,安装到/usr/local/mysql/,安装步骤略…
建一个数据库dns
CREATE DATABASE dns;
建一个表dns_records

use dns;
CREATE TABLE dns_records (
zone varchar (255),
host varchar (255),
type varchar (255),
data varchar (255),
ttl int(11),
mx_priority varchar (255),
refresh int(11),
retry int(11),
expire int(11),
minimum int(11),
serial bigint(20),
resp_person varchar (255),
primary_ns varchar (255)
);
加入一条记录
INSERT INTO `dns_records` ( `zone` , `host` , `type` , `data` , `ttl` , `mx_priority`
, `refresh` , `retry` , `expire` , `minimum` , `serial` , `resp_person` , `primary_ns` ) VALUES ( ‘yemaosheng.com’, ‘*’, ‘A’, ‘192.168.0.1′, ‘800′, NULL , NULL , ‘10′, NULL ,
NULL , NULL , NULL , NULL );

cp /usr/local/mysql/lib/mysql/libmysqlclient.so.15 /usr/lib/

启动Bind
./named -u root -g -d 1

发表在 article | 标签为 , | bind dlz 安装配置已关闭评论

mysql与php时间格式化参数参考

为方便查阅,从官方网站上转载的。因为mysql还有php的时间格式化参数不同,不小心会搞混,这里整理一番

PHP

format character Description Example returned values
Day
d Day of the month, 2 digits with leading zeros 01 to 31
D A textual representation of a day, three letters Mon through Sun
j Day of the month without leading zeros 1 to 31
l (lowercase ‘L’) A full textual representation of the day of the week Sunday through Saturday
N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) 1 (for Monday) through 7 (for Sunday)
S English ordinal suffix for the day of the month, 2 characters st, nd, rd or th. Works well with j
w Numeric representation of the day of the week 0 (for Sunday) through 6 (for Saturday)
z The day of the year (starting from 0) 0 through 365
Week
W ISO-8601 week number of year, weeks starting on Monday (added in PHP 4.1.0) Example: 42 (the 42nd week in the year)
Month
F A full textual representation of a month, such as January or March January through December
m Numeric representation of a month, with leading zeros 01 through 12
M A short textual representation of a month, three letters Jan through Dec
n Numeric representation of a month, without leading zeros 1 through 12
t Number of days in the given month 28 through 31
Year
L Whether it’s a leap year 1 if it is a leap year, 0 otherwise.
o ISO-8601 year number. This has the same value as Y, except that if the ISO week number (W) belongs to the previous or next year, that year is used instead. (added in PHP 5.1.0) Examples: 1999 or 2003
Y A full numeric representation of a year, 4 digits Examples: 1999 or 2003
y A two digit representation of a year Examples: 99 or 03
Time
a Lowercase Ante meridiem and Post meridiem am or pm
A Uppercase Ante meridiem and Post meridiem AM or PM
B Swatch Internet time 000 through 999
g 12-hour format of an hour without leading zeros 1 through 12
G 24-hour format of an hour without leading zeros 0 through 23
h 12-hour format of an hour with leading zeros 01 through 12
H 24-hour format of an hour with leading zeros 00 through 23
i Minutes with leading zeros 00 to 59
s Seconds, with leading zeros 00 through 59
u Microseconds (added in PHP 5.2.2) Example: 654321
Timezone
e Timezone identifier (added in PHP 5.1.0) Examples: UTC, GMT, Atlantic/Azores
I (capital i) Whether or not the date is in daylight saving time 1 if Daylight Saving Time, 0 otherwise.
O Difference to Greenwich time (GMT) in hours Example: +0200
P Difference to Greenwich time (GMT) with colon between hours and minutes (added in PHP 5.1.3) Example: +02:00
T Timezone abbreviation Examples: EST, MDT
Z Timezone offset in seconds. The offset for timezones
west of UTC is always negative, and for those east of UTC is
always positive.
-43200 through 50400
Full Date/Time
c ISO 8601 date (added in PHP 5) 2004-02-12T15:19:21+00:00
r » RFC 2822 formatted date Example: Thu, 21 Dec 2000 16:01:07 +0200
U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) See also time()

Unrecognized characters in the format string will be printed as-is. The Z format will always return 0 when using gmdate().

Note: Since this function only accepts integer timestamps the u format character is only useful when using the date_format() function with user based timestamps created with date_create().

MySQL

Specifier Description
%a Abbreviated weekday name (Sun..Sat)
%b Abbreviated month name (Jan..Dec)
%c Month, numeric (0..12)
%D Day of the month with English suffix (0th, 1st, 2nd, 3rd, …)
%d Day of the month, numeric (00..31)
%e Day of the month, numeric (0..31)
%f Microseconds (000000..999999)
%H Hour (00..23)
%h Hour (01..12)
%I Hour (01..12)
%i Minutes, numeric (00..59)
%j Day of year (001..366)
%k Hour (0..23)
%l Hour (1..12)
%M Month name (January..December)
%m Month, numeric (00..12)
%p AM or PM
%r Time, 12-hour (hh:mm:ss followed by AM or PM)
%S Seconds (00..59)
%s Seconds (00..59)
%T Time, 24-hour (hh:mm:ss)
%U Week (00..53), where Sunday is the first day of the week
%u Week (00..53), where Monday is the first day of the week
%V Week (01..53), where Sunday is the first day of the week; used with %X
%v Week (01..53), where Monday is the first day of the week; used with %x
%W Weekday name (Sunday..Saturday)
%w Day of the week (0=Sunday..6=Saturday)
%X Year for the week where Sunday is the first day of the week, numeric, four digits; used with %V
%x Year for the week, where Monday is the first day of the week, numeric, four digits; used with %v
%Y Year, numeric, four digits
%y Year, numeric (two digits)
%% A literal “%” character
%x x, for any “x” not listed above
发表在 db | 标签为 | mysql与php时间格式化参数参考已关闭评论