设计模式

一、设计模式大致分为三大类:创建型模式、结构型模式和行为型模式。

1、单例模式:保证一个类只有一个实例,提供一个访问它的全局访问点。

<懒汉模式>
优点->是延迟加载(需要的时候才去加载),适合单线程操作
缺点->是非线程安全的,在多线程中很容易出现不同步的情况

public class Singleton {  
    /* 私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */  
    private static Singleton instance = null;  

    /* 私有构造方法,防止被实例化 */  
    private Singleton() {}  

    /* 1:懒汉式,静态工程方法,创建实例 */  
    public static Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
}

双重线程检查
优点->延迟加载,线程安全
缺点->写法复杂,不简洁

public class SingletonInner { 
    /* volatile保证每个线程能够获取该变量的最新值,从而避免出现数据脏读的现象*/ 
    private static volatile SingletonInner sInst = null;  

    /* 私有的构造函数 */  
    private SingletonInner() {}  

    public static SingletonInner getInstance() {  
        SingletonInner inst = sInst;  // 创建临时变量
        if (inst == null) {
            synchronized (SingletonInner.class) {
                inst = sInst;
                if (inst == null) {
                    inst = new SingletonInner();
                    sInst = inst;
                }
            }
        }
        return inst;  // 注意这里返回的是临时变量
    }

内部类的实现
优点:延迟加载,线程安全(java中class加载时互斥的),也减少了内存消耗,推荐使用内部类方式。

public class SingletonInner {  
    /* 内部类实现单例模式,延迟加载,减少内存开销 */  
    private static class SingletonHolder {  
        private static SingletonInner instance = new SingletonInner();  
    }  

    /* 私有的构造函数 */  
    private SingletonInner() {}  

    public static SingletonInner getInstance() {  
        return SingletonHolder.instance;  
    }  
}  

<饿汉模式>
优点->是线程安全的,以空间换时间

public class Singleton {
    //将构造方法私有化,不允许外部直接创建对象
    private Singleton(){}

    //创建类的唯一实例,使用private static修饰
    private static Singleton instance = new Singleton();

    //提供一个用于获取实例的方法,使用public static修饰
    public static Singleton getInstance(){
        return instance;
    }
}

2、工厂模式: 为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。
<简单工厂模式Simple Factory>
又称为静态工厂方法模式,不利于产生系列产品

public class Factory{ //getClass 产生Sample 一般可使用动态类装载装入类。
    public static Sample creator(int which){ 
        if (which==1)
            return new SampleA();
        else if (which==2)
            return new SampleB();
    }
}

<工厂方法模式Factory Method>
是简单工厂模式的进一步抽象化和推广,工厂方法模式里不再只由一个工厂类决定那一个产品类应当被实例化,这个决定被交给抽象工厂的子类去做。

//抽象产品角色
public interface Moveable {
    void run();
}
//具体产品角色
public class Plane implements Moveable {
    @Override
    public void run() {
        System.out.println("plane....");
    }
}
//具体产品角色
public class Broom implements Moveable {
    @Override
    public void run() {
        System.out.println("broom.....");
    }
}
//抽象工厂
public abstract class VehicleFactory {
    abstract Moveable create();
}
//具体工厂
public class PlaneFactory extends VehicleFactory{
    public Moveable create() {
    return new Plane();
    }
}
//具体工厂
public class BroomFactory extends VehicleFactory{
    public Moveable create() {
        return new Broom();
    }
}
//测试类
public class Test {
    public static void main(String[] args) {
        VehicleFactory factory = new BroomFactory();
        Moveable m = factory.create();
        m.run();
    }
}

3、观察者模式: 又叫发布-订阅(Publish/Subscribe)模式。定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

/**  
* Subject(目标,Subject):    
* 目标知道它的观察者。可以有任意多个观察者观察同一个目标。  
* 提供注册和删除观察者对象的接口。  
*/  
public interface Subject {  
    public void attach(Observer mObserver);  
    public void detach(Observer mObserver);        
    public void notice();  
}

/**  
* Observer(观察者,Observer):  
* 为那些在目标发生改变时需要获得通知的对象定义一个更新接口。   
*/  
public interface Observer {  
    public void update();  
}  

/**  
* ConcreteSubject(具体目标,Teacher)  
* 将有关状态存入各ConcreteObserve对象。  
* 当他的状态发生改变时,向他的各个观察者发出通知。   
*/  
public class Teacher implements Subject{  

    private String phone;  
    private Vector students;  

    public Teacher(){  
        phone = "";  
        students = new Vector();  
    }  

    @Override  
    public void attach(Observer mObserver) {  
        students.add(mObserver);  
    }  

    @Override  
    public void detach(Observer mObserver) {  
        students.remove(mObserver);  
    }  

    @Override  
    public void notice() {  
        for(int i=0;i<students.size();i++){  
            ((Observer)students.get(i)).update();  
        }  
    }  

    public String getPhone() {  
        return phone;  
    }  

    public void setPhone(String phone) {  
        this.phone = phone;  
        notice();  
    }  
}

/**  
* ConcreteObserver(具体观察者, Student):  
* 维护一个指向ConcreteSubject对象的引用。  
* 存储有关状态,这些状态应与目标的状态保持一致。  
* 实现Observer的更新接口以使自身状态与目标的状态保持一致。  
*/  
public class Student implements Observer{  

    private String name;  
    private String phone;  
    private Teacher mTeacher;  

    public Student(String name,Teacher t){  
        this.name = name;  
        mTeacher = t;  
    }  

    public void show(){  
        System.out.println("Name:"+name+"\nTeacher'sphone:" + phone);  
    }  

    @Override  
    public void update() {  
        phone = mTeacher.getPhone();  
    }  
}

/**  
* 观察者(Observer)模式测试类   
*/  
public class ObserverClient {  
    public static void main(String[] args) {  
        Vector students = new Vector();  
        Teacher t = new Teacher();  
        for(int i= 0;i<10;i++){  
            Student st = new Student("Andy.Chen"+i,t);  
            students.add(st);  
            t.attach(st);  
        }  

        System.out.println("Welcome to Andy.Chen Blog!" +"\n"   
            +"Observer Patterns." +"\n"  
            +"-------------------------------");  

        t.setPhone("12345678");  
        for(int i=0;i<3;i++)  
            ((Student)students.get(i)).show();  

        t.setPhone("87654321");  
        for(int i=0;i<3;i++)  
            ((Student)students.get(i)).show();  
    }  
} 

STL

一、C++标准模板库STL:基本的6个组成部件为容器、算法、迭代器、仿函数、适配器和空间分配器。

1、C++智能指针: C++11中引入了智能指针的概念,方便管理堆内存。从三个层次理解智能指针

a、从较浅的层面看,智能指针是利用了一种叫做RAII(资源获取即初始化)的技术对普通的指针进行封装,这使得智能指针实质是一个对象,行为表现的却像一个指针。
b、智能指针的作用是防止忘记调用delete释放内存和程序异常的进入catch块忘记释放内存。另外指针的释放时机也是非常有考究的,多次释放同一个指针会造成程序崩溃,这些都可以通过智能指针来解决。
c、智能指针还有一个作用是把值语义转换成引用语义。C++和Java有一处最大的区别在于语义不同,在Java里面下列代码:
    Animal a = new Animal();
    Animal b = a;
    这里其实只生成了一个对象,a和b仅仅是把持对象的引用而已。但在C++中不是这样,
    Animal a;
    Animal b = a;
    这里却是就是生成了两个对象。

2、智能指针的使用:智能指针在C++11版本之后提供,包含在头文件中,auto_ptr、shared_ptr、unique_ptr、weak_ptr

3、auto_ptr:是C++98提供的解决方案,C+11已将将其摒弃,并提供了另外两种解决方案。然而,虽然auto_ptr被摒弃,但它已使用了好多年:同时,如果您的编译器不支持其他两种解决力案,auto_ptr将是唯一的选择。

4、shared_ptr的使用:shared_ptr多个指针指向相同的对象。shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,自动删除所指向的堆内存。shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁。

初始化:智能指针是个模板类,可以指定类型,传入指针通过构造函数初始化。也可以使用make_shared函数初始化。不能将指针直接赋值给一个智能指针,一个是类,一个是指针。例如std::shared_ptr<int> p4 = new int(1);的写法是错误的
拷贝和赋值:拷贝使得对象的引用计数增加1,赋值使得原对象引用计数减1,当计数为0时,自动释放内存。后来指向的对象引用计数加1,指向后来的对象。
get函数获取原始指针
注意不要用一个原始指针初始化多个shared_ptr,否则会造成二次释放同一内存
注意避免循环引用:shared_ptr的一个最大的陷阱是循环引用,循环,循环引用会导致堆内存无法正确释放,导致内存泄漏。循环引用在weak_ptr中介绍。

int main()
{
    int a = 10;

    std::shared_ptr<int> ptra = std::make_shared<int>(a);
    std::cout << ptra.use_count() << std::endl;//输出1

    std::shared_ptr<int> ptra2(ptra); //copy,计数加1
    std::cout << ptra.use_count() << ptra2.use_count()<< std::endl;
    //输出22

    int b = 20;
    int *pb = &a;

    //std::shared_ptr<int> ptrb = pb;  //error
    std::shared_ptr<int> ptrb = std::make_shared<int>(b);

    ptra2 = ptrb; //assign
    pb = ptrb.get(); //获取原始指针

    std::cout << ptra.use_count() << std::endl;
    std::cout << ptrb.use_count() << std::endl;

}

5、unique_ptr的使用:同一时刻只能有一个unique_ptr指向给定对象(通过禁止拷贝语义、只有移动语义来实现)。相比与原始指针unique_ptr用于其RAII的特性,使得在出现异常的情况下,动态资源能得到释放。

unique_ptr指针本身的生命周期:从unique_ptr指针创建时开始,直到离开作用域。离开作用域时,若其指向对象,则将其所指对象销毁(默认使用delete操作符,用户可指定其他操作)。
unique_ptr指针与其所指对象的关系:在智能指针生命周期内,可以改变智能指针所指对象,如创建智能指针时通过构造函数指定、通过reset方法重新指定、通过release方法释放所有权、通过移动语义转移所有权。
int main(){
    {
        std::unique_ptr<int> uptr(new int(10));  //绑定动态对象
        //std::unique_ptr<int> uptr2 = uptr;  //不能賦值
        //std::unique_ptr<int> uptr2(uptr);  //不能拷貝
        std::unique_ptr<int> uptr2 = std::move(uptr); //轉換所有權
        uptr2.release(); //释放所有权
    }
    //超過uptr的作用域,內存釋放
}

6、weak_ptr的使用:是为了配合shared_ptr而引入的一种智能指针,因为它不具有普通指针的行为。没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。weak_ptr可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。

使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count()==0,但更快,表示被观测的资源(也就是shared_ptr的管理的资源)已经不复存在。
weak_ptr可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象,从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr。
int main() {
    {
        std::shared_ptr<int> sh_ptr = std::make_shared<int>(10);
        std::cout << sh_ptr.use_count() << std::endl;

        std::weak_ptr<int> wp(sh_ptr);
        std::cout << wp.use_count() << std::endl;

        if(!wp.expired()){
            std::shared_ptr<int> sh_ptr2 = wp.lock(); 
            //get another shared_ptr
            *sh_ptr = 100;
            std::cout << wp.use_count() << std::endl;
        }
    }
    //delete memory
}

7、循环引用

8、常用的类或容器:string、vector、set、list、map

a、string

    1)、C语言使用字符串
        char *ptr = “hello”;//创建指针指向字符串常量,这段字符串我们是不能修改的,编译不会报错,但会有警告,应该如下
        char const *ptr = “hello”;
        char s2[20] = "Hello”;//可以修改的字符串或如下
        char s3[] = "Hello";
        char* s4 = (char*)malloc(20);//动态分配内存
    2)、C++ 标准库中的string表示可变长的字符串,它在头文件string里面。
        string s1;//初始化字符串,空字符串
        string s2 = s1; //拷贝初始化,深拷贝字符串,s2是s1的副本
        string s3 = "I am Yasuo"; //直接初始化,s3存了字符串
        string s4(10, 'a'); //s4存的字符串是aaaaaaaaaa
        string s5(s4); //拷贝初始化,深拷贝字符串
        string s6("I am Ali"); //直接初始化        
        string s7 = string(6, 'c'); //拷贝初始化,cccccc

b、vector:好比是C语言中的数组,包含头文件vector

    1)、如果vector的元素类型是int,默认初始化为0
        如果vector元素类型为string,则默认初始化为空字符串。
    2)、初始化
        vector<int> v1;//v1是空vector,潜在元素类型为int,执行默认初始化(为0)
        vector<string> v2;//v2,潜在元素类型为string
        vector<int> v5 = { 1,2,3,4,5 }; //列表初始化,注意使用的是花括号
        vector<string> v6 = { "hi","my","name","is","lee" };
        vector<int> v7(5, -1); //初始化为-1,-1,-1,-1,-1。第一个参数是数目,第二个参数是要初始化的值
        vector<string> v8(3, "hi");
        vector<int> v9(10); //默认初始化为0
        vector<int> v10(4); //默认初始化为空字符串
    3)、push_back:数组尾部加入元素。push_back的作用有两个:告诉编译器为新元素开辟空间、将新元素存入新空间里。pop_back删除末尾元素
        vector<int> v1(2);//定义了vector,有两个元素,初始化都为0
        v1[0] = 10;
        v1[1] = 20;
        v1.push_back(30);//那么会在尾部添加一个元素且值为30, pos为2(即v1[2])
        vector<int> vec;
        vec[0] = 1; //错误!编译器不会报错,就像是数组越界。
    4)、    vector<int> v1 = { 1,2,3,4,5 }; //列表初始化,注意使用的是花括号,c++11标准,
        //编译时加-std=c++11
        v1.push_back(6);//加入一个元素初始化值为6,并把它放在最后
        v1.pop_back(); //删除最后一个元素
        v1.insert(v1.begin()+1,9); //在第二个位置插入新元素

c、set:跟vector差不多,跟vector的唯一区别就是,set里面的元素是有序的且唯一的。只要你往set里添加元素,它就会自动排序,而且,如果你添加的元素set里面本来就存在,那么这次添加操作就不执行。要想用set先加个头文件set。


d、list:是一个双向链表,而单链表对应的容器则是foward_list。双向链表的优点是插入和删除元素都比较快捷,缺点是不能随机访问元素。

e、map:运用了哈希表地址映射的思想,也就是key-value的思想,来实现的。

9、迭代器:是一种检查容器内元素并遍历元素的数据类型。C++更趋向于使用迭代器而不是下标操作。迭代器iterator就是一种智能指针。它对原始指针进行了封装,而且提供一些等价于原始指针的操作,做到既方便又安全。

a、每种容器都定义了自己的迭代器类型,入vector
    vector<int>::iterator    iter;//定义一个名为iter的变量
b、每种容器都定义了一对名为begin和end的函数,用于返回迭代器。
    vector<int>    ivec;

    //将迭代器iter1初始化为指向ivec容器的第一个元素
    vector<int>::iterator  iter1=ivec.bengin();

    //将迭代器iter2初始化为指向ivec容器的最后一个元素的下一个位置
    vector<int>::iterator   iter2=ivec.end();
    注意end并不指向容器的任何元素,而是指向容器的最后元素的下一位置,称为超出末端迭代器。
    如果vector为空,则begin返回的迭代器和end返回的迭代器相同。一旦向上面这样定义和初始化,
    就相当于把该迭代器和容器进行了某种关联,就像把一个指针初始化为指向某一空间地址一样。

c、迭代器的常用运算操作:
    *iter   //对iter进行解引用,返回迭代器iter指向的元素的引用
    iter->men  //对iter进行解引用,获取指定元素中名为men的成员。等效于(*iter).men
    ++iter     //给iter加1,使其指向容器的下一个元素
    iter++
    --iter     //给iter减1,使其指向容器的前一个元素
    iter--
    iter1==iter2  //比较两个迭代器是否相等,当它们指向同一个容器的同一个元素或者都指向同一个容器的超出末端的下一个位置时,它们相等 
    iter1!=iter2 

d、在C++定义的容器类型中,只有vector和queue容器提供迭代器算数运算和除!=和==之外的关系运算

e、迭代器const_iterator:
    1)、每种容器还定义了一种名为const_iterator的类型。
    2)、该类型的迭代器只能读取容器中的元素,不能用于改变其值。普通的迭代器可以对容器中的元素进行解引用并修改,而const_iterator类型的迭代器只能用于读不能进行重写。
        //合法,读取容器中元素值
        for(vector<int>::const_iterator iter=ivec.begin();iter!=ivec.end();++iter)
            cout << *iter << endl;    
        //不合法,不能进行写操作
        for(vector<int>::const_iterator iter=ivec.begin();iter!=ivec.end();++iter)
            *iter=0;
    3)、const_iterator和const iterator是不一样的,后者对迭代器进行声明时,必须对迭代器进行初始化,并且一旦初始化后就不能修改其值。这有点像常量指针和指针常量的关系。
        vector<int>  ivec(10);
        const    vector<int>::iterator iter = ivec.begin();
        *iter=0;   //合法,可以改变其指向的元素的值
        ++iter;    //不合法,无法改变其指向的位置

f、使迭代器失效的操作:由于一些对容器的操作如删除元素或移动元素等会修改容器的内在状态,这会使得原本指向被移动元素的迭代器失效,也可能同时使其他迭代器失效。使用无效的迭代器是没有定义的,可能会导致和使用悬垂指针相同的问题。所以在使用迭代器编写程序时,需要特别留意哪些操作会使迭代器失效。使用无效迭代器会导致严重的运行时错误。

C++

一、面向对象的四个基本特征:抽象、封装、继承、多态(抽象、继承、封装是多态的基础,多态是抽象、封装、继承的表现)

1、32位机器上,指针sizeof为4个字节,64位机器上,指针sizeof为8个字节

2、空类也会被实例化,所以空类的sizeof为1个字节,非空类的sizeof就涉及到字节对齐问题

3、在没有特殊注明字节对齐时,系统会以默认的字节对齐规则进行字节对齐(常见对齐字节:1、2、4、8、16)

4、#pragma pack(push,A字节)指明字节对齐规则以A字节为准,A也只能为(1、2、4、8、16),#pragma pack(pop)为释放对齐规则(以64位机器为例)

class A{ 
    char a[2]; 
    char *p; 
}; 
sizeof(A对象) 为16

#pragma pack(push,4)
class A{ 
    char a[2]; 
    char *p; 
};
#pragma pack(pop)
sizeof(A对象) 为12,如果把4改为2字节对齐,则结果为10
注:在没指明字节对齐规则时,默认对齐方式以最大数据结构所占字节对齐,内存申请按顺序依次开辟空间,所以同样的数据类型不同顺序都会影响内存大小

5、虚函数:在C++中,基类必须将它的两种成员函数区分开来,一种是基类希望其派生类进行覆盖的函数;另一种是基类希望派生类直接继承而不要改变的函数。对于前者,基类通过在函数之前加上virtual关键字将其定义为虚函数。

a. 一旦基类的某个函数被声明成虚函数,则所有派生类中它都是默认为虚函数,不论加没加virtual关键字。
b. 任何构造函数之外的非静态函数都可以是虚函数。(类中的构造函数和静态函数不能为虚函数)
c. 如果派生类没有覆盖其基类中某个虚函数,则该虚函数的行为类似于其他的普通成员,派生类会直接继承其在基类中的版本。

6、纯虚函数:基类中不能对虚函数给出有意义的实现。为了让虚函数在基类什么也不做,在虚函数体声明后面加上”=0”就是纯虚函数了。

a. 有纯虚函数的类叫抽象类,是不能new对象的。

Read More

开放系统互联

开放系统互联(Open System Interconnect,OSI)意思是开放式系统互联

1、应用层(Application Layer):数据传送的单位<数据报>

  • 是通信用户之间的窗口,为用户提供网络管理、文件传输、事务处理等服务,在OSI的7个层次中,应用层是最复杂的,所包含的应用层协议也是最多的,具有代表性的协议如下
    Telnet:远程终端协议
    FTP:文件传输协议(File Transfer Protocol)
    HTTP:超文本传输协议(HyperText Transfer Protocol)
    SNMP:简单网络管理协议(Simple Network Management Protocol )
    SMTP:简单邮件传输协议(Simple Mail Transfer Protocol)
    DNS:域名服务协议(Domain Name System,DNS)
    POP3:邮局协议版本3(Post Office Protocol - Version 3)

Read More

常见排序算法及时间复杂度


  • 选择排序

1、首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置

2、再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾

3、将两个排序好的子序列合并成一个最终的排序序列,直到所有元素均排序完毕

4、选择排序是非常稳定的

5、无论什么数据进去时间复杂度都是 O(n2)

6、所以用到它的时候,数据规模越小越好

7、选择排序,实例代码如下.

#include <stdio.h>

#define LEN   10
int data[LEN] = {10, 1, 6, 3, 4, 8, 2, 9, 5, 0};


void print_data(void)
{
    printf("%d %d %d %d %d %d %d %d %d %d\n",
            data[0], data[1], data[2], data[3],
            data[4], data[5], data[6], data[7],
            data[8], data[9]);
}

int main(int argc, char *argv[])
{
    int i, j, temp;

    print_data();

    for(i = 0; i < LEN-1; i++){
        for(j = i+1; j < LEN; j++) {
            if(data[i] > data[j]) {//找最小的数
                temp = data[i];
                data[i] = data[j];
                data[j] = temp;
            }
            print_data();
        }
    }

    return 0;
}

Read More

SQL


  • 简介

SQL 是用于访问和处理数据库的标准的计算机语言。
是一门 ANSI 的标准计算机语言,用来访问和操作数据库系统。SQL 语句用于取回和更新数据库中的数据。
SQL 可与数据库程序协同工作,比如 MS Access、DB2、Informix、MS SQL Server、Oracle、Sybase 
以及其他数据库系统。
不幸地是,存在着很多不同版本的 SQL 语言,但是为了与 ANSI 标准相兼容,它们必须以相似的方式共同地来
支持一些主要的关键词(比如 SELECT、UPDATE、DELETE、INSERT、WHERE 等等)。

注释:除了 SQL 标准之外,大部分 SQL 数据库程序都拥有它们自己的私有扩展!

1、什么是 SQL?

  • SQL 指结构化查询语言
  • SQL 使我们有能力访问数据库
  • SQL 是一种 ANSI 的标准计算机语言,ANSI是美国国家标准化组织

2、SQL 能做什么?

  • SQL 面向数据库执行查询
  • SQL 可从数据库取回数据
  • SQL 可在数据库中插入新的记录
  • SQL 可更新数据库中的数据
  • SQL 可从数据库删除记录
  • SQL 可创建新数据库
  • SQL 可在数据库中创建新表
  • SQL 可在数据库中创建存储过程
  • SQL 可在数据库中创建视图
  • SQL 可以设置表、存储过程和视图的权限

  • 语法

1、SELECT语句:用于从表中查找数据,结果被存储在一个结果表中(称为结果集)

SELECT name,age FROM table               查出表中name字段和age字段的所有数据
SELECT DISTINCT age FROM table           查出表中age字段中所有不重复的数据(DISTINCT 去重)
SELECT * FROM table                      查出表中所有字段的所有数据
SELECT name FROM table WHERE name='张三'  查出表中姓名是张三的数据
SELECT * FROM table WHERE name='李四' AND age=20  查出表中姓名是李四并且年龄为20岁的数据
SELECT name, age FROM table ORDER BY age         查出表中name字段和age字段的数据并按age升序排序
SELECT name, age FROM table ORDER BY age DESC    查出表中name字段和age字段的数据并按age降序排序

2、INSERT INTO语句:用于向表格中插入新的行

INSERT INTO table VALUES (值1, 值2,....)          向表中插入一条新的记录
INSERT INTO table (name, age) VALUES ('张三', 18) 向表中插入一条新的记录并指定赋值

3、UPDATE语句:用于修改表中的数据

UPDATE table SET age=20 WHERE name='李四'             将表中姓名为李四的记录的年龄改为20岁
UPDATE table SET age=20,sex='男' WHERE name='李四'    将表中姓名为李四的记录的年龄改为20岁且性别改为男

4、DELETE语句:用于删除表中的行

DELETE FROM table WHERE name='张三'   删除表中姓名为张三的所有记录
DELETE * FROM table                  删除表中所有的数据记录

Markdown

一种轻量级的标记语言,可以被编译成 Html 页面.

简要语法规则如下:

1、标题

一级标题: #
二级标题: ##
三级标题: ###
四级标题: ####

Read More