大端与小端,数据库事务,锁等近期C++笔试概要(2)

事务(Transaction),是指访问并可能更新数据库中各种数据项的一个程序执行单元(Unit),保持逻辑数据一致性与可恢复性。

事务通常是由用户编写的程序执行所引起的,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。例如:在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。 
事务是恢复和并发控制的基本单位。具有四个属性:原子性、一致性、阻离性、持久性,合起来通常被称为ACID特性。 
1、原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。 
2、一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。 
3、隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。 
4、持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响

SQL Server中事务被分为3类常见的事务

自动提交事务:是SQL Server默认的一种事务模式,每条Sql语句都被看成一个事务进行处理,你应该没有见过,一条Update 修改2个字段的语句,只修该了1个字段而另外一个字段没有修改。。

显式事务:T-sql标明,由Begin Transaction开启事务开始,由Commit Transaction 提交事务、Rollback Transaction 回滚事务结束。

隐式事务:使用Set IMPLICIT_TRANSACTIONS ON 将将隐式事务模式打开,不用Begin Transaction开启事务,当一个事务结束,这个模式会自动启用下一个事务,只用Commit Transaction 提交事务、Rollback Transaction 回滚事务即可。

在多用户都用事务同时访问同一个数据资源的情况下,就会造成以下几种数据错误

更新丢失:多个用户同时对一个数据资源进行更新,必定会产生被覆盖的数据,造成数据读写异常。

不可重复读:如果一个用户在一个事务中多次读取一条数据,而另外一个用户则同时更新啦这条数据,造成第一个用户多次读取数据不一致。

脏读:第一个事务读取第二个事务正在更新的数据表,如果第二个事务还没有更新完成,那么第一个事务读取的数据将是一半为更新过的,一半还没更新过的数据,这样的数据毫无意义。

幻读:第一个事务读取一个结果集后,第二个事务,对这个结果集经行增删操作,然而第一个事务中再次对这个结果集进行查询时,数据发现丢失或新增。

扫描二维码关注公众号,回复: 3251290 查看本文章

锁定,使得一个事务对他自己的数据块进行操作的时候,而另外一个事务则不能插足这些数据块。

Q:如果事务T获得了数据对象Q上的S锁,则其他事务在数据对象Q上:可以加S锁。  -----S锁是共享锁,只能读不能写,如果被其被加X锁(排他锁),则其他事务不能加任何锁。

锁定从数据库系统的角度大致可以分为6种:

  • 共享锁(S):还可以叫他读锁。可以并发读取数据,但不能修改数据。也就是说当数据资源上存在共享锁的时候,所有的事务都不能对这个资源进行修改,直到数据读取完成,共享锁释放。
  • 排它锁(X):还可以叫他独占锁、写锁。就是如果你对数据资源进行增删改操作时,不允许其它任何事务操作这块资源,直到排它锁被释放,防止同时对同一资源进行多重操作
  • 更新锁(U):防止出现死锁的锁模式,两个事务对一个数据资源进行先读取在修改的情况下,使用共享锁和排它锁有时会出现死锁现象,而使用更新锁则可以避免死锁的出现。资源的更新锁一次只能分配给一个事务,如果需要对资源进行修改,更新锁会变成排他锁,否则变为共享锁。
  • 意向锁:SQL Server需要在层次结构中的底层资源上(如行,列)获取共享锁,排它锁,更新锁。例如表级放置了意向共享锁,就表示事务要对表的页或行上使用共享锁。在表的某一行上上放置意向锁,可以防止其它事务获取其它不兼容的的锁。意向锁可以提高性能,因为数据引擎不需要检测资源的每一列每一行,就能判断是否可以获取到该资源的兼容锁。意向锁包括三种类型:意向共享锁(IS),意向排他锁(IX),意向排他共享锁(SIX)。
  • 架构锁:防止修改表结构时,并发访问的锁。
  • 大容量更新锁:允许多个线程将大容量数据并发的插入到同一个表中,在加载的同时,不允许其它进程访问该表。

死锁耗时耗资源,然而在大型数据库中,高并发带来的死锁是不可避免的,所以我们只能让其变的更少。

  1. 按照同一顺序访问数据库资源,上述例子就不会发生死锁啦
  2. 保持是事务的简短,尽量不要让一个事务处理过于复杂的读写操作。事务过于复杂,占用资源会增多,处理时间增长,容易与其它事务冲突,提升死锁概率。
  3. 尽量不要在事务中要求用户响应,比如修改新增数据之后在完成整个事务的提交,这样延长事务占用资源的时间,也会提升死锁概率。
  4. 尽量减少数据库的并发量。
  5. 尽可能使用分区表,分区视图,把数据放置在不同的磁盘和文件组中,分散访问保存在不同分区的数据,减少因为表中放置锁而造成的其它事务长时间等待。
  6. 避免占用时间很长并且关系表复杂的数据操作。
  7. 使用较低的隔离级别,使用较低的隔离级别比使用较高的隔离级别持有共享锁的时间更短。这样就减少了锁争用。

1个字节 char*(即指针变量): 在类中,如果什么都没有,则类占用1个字节,一旦类中有其他的占用空间成员,则这1个字节就不在计算之内,如一个类只有一个int则占用4字节而不是5字节。

如果只有成员函数,则还是只占用1个字节,因为类函数不占用空间

虚函数因为存在一个虚函数表,需要4个字节,数据成员对象如果为指针则为4字节,注意有字节对齐,如果为13字节,则进位到16字节空间。

class A     
{     
};    
   A没有数据成员,也没有虚函数(不需要虚表指针),但语言规定类的大小不能为0,所以长度为1;
class B     
{  
    char ch;     
    virtual void func0()  {  }   
};   B一个虚表指针再加一个char,4+1=5,然后字节对齐到指针类型的整数倍,所以是8;

class C    
{  
    char ch1;  
    char ch2;  
    virtual void func()  {  }    
    virtual void func1()  {  }   
};  C一个虚表指针再加两个char,4+2=6,然后字节对齐到指针类型的整数倍,也是8;

class D: public A, public C  
{     
    int d;     
    virtual void func()  {  }   
    virtual void func1()  {  }  
};     
D继承自一个空类(A)和一个size为8的类(C),虽然类的大小不能为0,但类做基类时,子对象的空间却可以为0,所以A类子对象不占空间;另外考虑到C类子对象中已经有虚表指针,所以不再额外需要虚表指针,只需要再加上D自己的一个int成员,所以size为8+4=12;12已经是指针或int类型的整数倍了,无需再对齐。

class E: public B, public C  
{     
    int e;     
    virtual void func0()  {  }   
    virtual void func1()  {  }  
};  
E比较简单,就是两个父类子对象的大小(8,8),再加上E自己的int成员(4),不需要再对齐,所以是20。有一点需要清楚的是,虽然两个父类都有虚函数,但两个父类自己原本也都已有虚表指针的空间,所以不再需要额外的。

大端、小端:

如果把一个数看成一个字符串,比如11223344看成"11223344",末尾是个'\0','11'到'44'个占用一个存储单元,那么它的尾端很显然是44,前面的高还是低就表示尾端放在高地址还是低地址,它在内存中的放法非常直观,如下图:

0x11223344:

大端:0x11223344

小端:0x44332211

#include <stdio.h>

int main()
{
    unsigned int x = 0x12345678;

    if (*(char *)&x == 0x78)
    {
        printf("little-endian.\n");
    }
    else if (*(char *)&x == 0x12)
    {
        printf("big-endian\n");
    }
    else
    {
        printf("confused.\n");
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/single6/article/details/82657533