【9159.com】在表被创建或者删除的时候执行sql语句

作者: 编程  发布:2019-11-05

阻止并发下的产品超卖思路是利用redis串行处理数据,但又有高并发处理数据的能力

ServiceStack.OrmLite 笔记2

这篇主要介绍 增加

db.Insert(new Employee { Id = 1, Name = "Employee 1" }); //默认同步

await db.InsertAsync(new Employee { Id = 1, Name = "Employee 1" }); //异步 其他的异步类似这里的这个示例

db.InsertOnly(new Person { FirstName = "Amy" }, q => q.Insert(p => new {p.FirstName}))
// 插入部分字段 后面的参数q.Insert表示要插入的字段 生成sql: INSERT INTO "Person" ("FirstName") VALUES ('Amy')

var rowId = db.Insert(new Poco { Text = "Text" }, selectIdentity:true);// selectIdentity:true返回自增长的id

这里代码有点多 全局的插入时过滤 类似的有UpdateFilter ,感觉就是插入时对数据进行拦截,可以发挥你的想象,比如可以在这里加日志,或者扩展新的字段,做爱做的事情。
public interface IAudit
{
DateTime CreatedDate { get; set; }
DateTime ModifiedDate { get; set; }
string ModifiedBy { get; set; }
}

//表对应的类
public class AuditTableA : IAudit
{
public AuditTableA()
{
this.CreatedDate = this.ModifiedDate = DateTime.UtcNow;
}

    [AutoIncrement]
    public int Id { get; set; }
    public DateTime CreatedDate { get; set; }
    public DateTime ModifiedDate { get; set; }
    public string ModifiedBy { get; set; }
}

OrmLiteConfig.InsertFilter = (dbCmd, row) => {
var auditRow = row as IAudit;
if (auditRow != null)
auditRow.CreatedDate = auditRow.ModifiedDate = DateTime.UtcNow;
};
下面是上面方法的新体位,也来自官网。对数据进行验证
OrmLiteConfig.InsertFilter = OrmLiteConfig.UpdateFilter = (dbCmd, row) => {
var auditRow = row as IAudit;
if (auditRow != null && auditRow.ModifiedBy == null)
throw new ArgumentNullException("ModifiedBy");
};

try
{
db.Insert(new AuditTable());
}
catch (ArgumentNullException) {
//throws ArgumentNullException
}

db.Insert(new AuditTable { ModifiedBy = "Me!" }); //succeeds

下面的代码因为也有insert 就也放上吧
在表被创建或者删除的时候执行sql语句
[PostCreateTable("INSERT INTO TableWithSeedData (Name) VALUES ('Foo');"

  • "INSERT INTO TableWithSeedData (Name) VALUES ('Bar');")]
    public class TableWithSeedData
    {
    [AutoIncrement]
    public int Id { get; set; }
    public string Name { get; set; }
    }

typeof(TableWithSeedData)
.AddAttributes(new PostCreateTableAttribute(
"INSERT INTO TableWithSeedData (Name) VALUES ('Foo');" +
"INSERT INTO TableWithSeedData (Name) VALUES ('Bar');"));

前戏和事后,都是可以有自己的玩法
[PreCreateTable(runSqlBeforeTableCreated)][PostCreateTable(runSqlAfterTableCreated)]
[PreDropTable(runSqlBeforeTableDropped)][PostDropTable(runSqlAfterTableDropped)]
public class Table {}

Db.ExecuteSql("INSERT INTO page_stats (ref_id, fav_count) VALUES (@refId, @favCount)", new { refId, favCount }) //直接执行sql语句

Db.ExecuteSqlAsync("UPDATE page_stats SET view_count = view_count + 1 WHERE id = @id", new { id })//直接执行sql语句

创建表

前一篇忘记写创建表了,这里补上。(其实前一篇也有那么一点)

建议安装源码里的t4模板看看效果先。

public 的属性才有效

在表被创建或者删除的时候执行sql语句
[PostCreateTable("INSERT INTO TableWithSeedData (Name) VALUES ('Foo');"

  • "INSERT INTO TableWithSeedData (Name) VALUES ('Bar');")]
    public class TableWithSeedData
    {
    [AutoIncrement]
    public int Id { get; set; }
    public string Name { get; set; }
    }

typeof(TableWithSeedData)
.AddAttributes(new PostCreateTableAttribute(
"INSERT INTO TableWithSeedData (Name) VALUES ('Foo');" +
"INSERT INTO TableWithSeedData (Name) VALUES ('Bar');"));

前戏和事后,都是可以有自己的玩法
[PreCreateTable(runSqlBeforeTableCreated)][PostCreateTable(runSqlAfterTableCreated)]
[PreDropTable(runSqlBeforeTableDropped)][PostDropTable(runSqlAfterTableDropped)]
public class Table {}

public class PocoTable
{
public int Id { get; set; }

[CustomField("CHAR(20)")] //这里是数据库的类型的字段的验证,和fluentvalidation 不太一样,fluentvalidation更多是对类的字段验证。 这里的 [CustomField("CHAR(20)")]是和ef差不多,是指和数据库的映射
public string CharColumn { get; set; }

[CustomField("DECIMAL(18,4)")]
public decimal? DecimalColumn { get; set; }

}
db.CreateTable();
生成sql:
CREATE TABLE "PocoTable"
(
"Id" INTEGER PRIMARY KEY,
"CharColumn" CHAR(20) NULL,
"DecimalColumn" DECIMAL(18,4) NULL
);

//外键和引用 建议自己建几个表,亲手撸一下。av看再多,不如约个来一发
public class TableWithAllCascadeOptions
{
[AutoIncrement] public int Id { get; set; }

[References(typeof(ForeignKeyTable1))]
public int SimpleForeignKey { get; set; }

[ForeignKey(typeof(ForeignKeyTable2), OnDelete = "CASCADE", OnUpdate = "CASCADE")]
public int? CascadeOnUpdateOrDelete { get; set; }

[ForeignKey(typeof(ForeignKeyTable3), OnDelete = "NO ACTION")]
public int? NoActionOnCascade { get; set; }

[Default(typeof(int), "17")]  //默认值
[ForeignKey(typeof(ForeignKeyTable4), OnDelete = "SET DEFAULT")]
public int SetToDefaultValueOnDelete { get; set; }

[ForeignKey(typeof(ForeignKeyTable5), OnDelete = "SET NULL")]
public int? SetToNullOnDelete { get; set; }

}

db.DropAndCreateTable();//删除然后添加表
dbFactory.Run(db => db.CreateTable(overwrite:false));//不解释 看姿势
db.CreateTable(true);// overwrite 直给

//批量添加 用事务
db.DropAndCreateTable();
var rows = "A,B,B,C,C,C,D,D,E".Split(',').Map(x => new LetterFrequency { Letter = x });
db.InsertAll(rows);

实现在这里
internal static void InsertAll(this IDbCommand dbCmd, IEnumerable objs)
{
IDbTransaction dbTrans = null;

        try
        {
            if (dbCmd.Transaction == null)
                dbCmd.Transaction = dbTrans = dbCmd.Connection.BeginTransaction();

            var dialectProvider = dbCmd.GetDialectProvider();

            dialectProvider.PrepareParameterizedInsertStatement<T>(dbCmd);

            foreach (var obj in objs)
            {
                if (OrmLiteConfig.InsertFilter != null)
                    OrmLiteConfig.InsertFilter(dbCmd, obj);

                dialectProvider.SetParameterValues<T>(dbCmd, obj);

                try
                {
                    dbCmd.ExecNonQuery();
                }
                catch (Exception ex)
                {
                    Log.Error("SQL ERROR: {0}".Fmt(dbCmd.GetLastSqlAndParams()), ex);
                    throw;
                }
            }

            if (dbTrans != null)
                dbTrans.Commit();
        }
        finally
        {
            if (dbTrans != null)
                dbTrans.Dispose();
        }
    }

实例测试Mysql使用索引带来的效率提升

产品表(product) 

 

class Product

创建数据库:

{

[sql] 

  public int Id{get;set} //自增Id

CREATE DATABASE `sql_learn_db`;  

       public string Name{get;set}//产品名称

  www.2cto.com  

       public int Number{get;set}//库存

创建一个表:

       public DateTime NTime{get;set;}//库存同步时间

[sql] 

       ....

Create Table: CREATE TABLE `persons` (  

}

  `Id` int(11) NOT NULL AUTO_INCREMENT,  

库存变更记录表(productNumberRecord)

  `LastName` varchar(255) DEFAULT NULL,  

class productNumberRecord

  `FirstName` varchar(255) DEFAULT NULL,  

{

  `9159.com,Address` varchar(255) DEFAULT NULL,  

  public int Id{get;set;}

  `City` varchar(255) DEFAULT NULL,  

       public int Number{get;set;} //本次消耗库存数量

  PRIMARY KEY (`Id`)  

       public int SurplusNumber{get;set} //本次消耗后的剩余数量

) ENGINE=InnoDB DEFAULT CHARSET=utf8  

       public DataTime Time{get;set;} //记录时间

 

       ....

表的结构: www.2cto.com  

}

[plain] 

1.将产品Id,库存存入redis,每次操作产品库存,则产生一条库存的变更记录存入sql库中

+-----------+--------------+------+-----+---------+----------------+  

2.此时sql库产品的实际库存应该是 库存=库存-库存记录(大于NTime时间的记录)

| Field     | Type         | Null | Key | Default | Extra          |  

3.sql库中的余额,可以做定时任务 按天或小时数进行同步,防止过大的记录造成select超时

+-----------+--------------+------+-----+---------+----------------+  

4.如果redis挂掉,那么它将从数据库中 按照步揍2的方式同步库存

| Id        | int(11)      | NO   | PRI | NULL    | auto_increment |  

 

| LastName  | varchar(255) | YES  |     | NULL    |                |  

伪代码实现(不加锁)

| FirstName | varchar(255) | YES  |     | NULL    |                |  

(开始事务){

| Address   | varchar(255) | YES  |     | NULL    |                |  

try{

| City      | varchar(255) | YES  |     | NULL    |                |  

func1(插入变更记录表);
如果func1 执行失败 直接跳出

+-----------+--------------+------+-----+---------+----------------+  

func3 ...

 

func4 ...

利用JDBC插入 1000000条数据。

等其他业务

 

funcX(增减redis库存)
如果funcX执行失败,直接跳出,不插入日志

DBIndexTest.java:

如果都成功 则提交事务

(请手动修改用户名和密码,并导入驱动包)

catch{
tran.callback()//事务回滚
}

[java] 

 

import java.sql.Connection;  

import java.sql.DriverManager;  

import java.sql.PreparedStatement;  

import java.sql.SQLException;  

import java.util.Random;  

  

  

public class DBIndexTest {  

  

    private static final String MYSQL_DRIVER = "com.mysql.jdbc.Driver";  

    private static final String DB_URL = "jdbc:mysql://localhost:3306/sql_learn_db";  

      

    private static final String USER_NAME = "root";  

    private static final String PASSWORD = "";  

      

    private static final String sql = "insert into persons values (null,?,?,'zjut','hangzhou')";  

      

    private static Connection conn = null;  

      

    private static PreparedStatement pstmt = null;  

      

    private static Random random = new Random();  

      

    private DBIndexTest(){};  

      

    public static String getRandomName() {  

        int fornum = 1 + random.nextInt(10);  /* 1~10 */  

        StringBuilder sb = new StringBuilder();  /* 97~122 */  

        for(int i=0; i<fornum;i++) {  

            sb.append((char)(97 + random.nextInt(26)));  

        }  

        return sb.toString();  

    }  

      

    private static void createConnection() {  

        try {  

            Class.forName(MYSQL_DRIVER);  

            conn = DriverManager.getConnection(DB_URL,USER_NAME,PASSWORD);  

        } catch (ClassNotFoundException e) {  

            // TODO Auto-generated catch block  

            e.printStackTrace();  

  

        } catch (SQLException e) {  

            // TODO Auto-generated catch block  

            e.printStackTrace();  

  

        }  

          

    }  

      

    public static Connection getConnection() {  

        if(conn == null) {  

            createConnection();  

        }  

        return conn;  

    }  

    public static void insertRecord() {  

        conn = getConnection();  

        try {  

            if(pstmt == null)  

                pstmt = conn.prepareStatement(sql);  

              

            pstmt.setString(1, getRandomName());  

            pstmt.setString(2, getRandomName());  

            int affect = pstmt.executeUpdate();  

            System.out.println(affect == 1 ? "插入成功!" : "插入失败!");  

              

        } catch (SQLException e) {  

            // TODO Auto-generated catch block  

            e.printStackTrace();  

        }  

    }  

      

    public static void main(String[] args) {  

        long start = System.currentTimeMillis();  

          

        for(int i=0; i< 1000000; i++) {  

            insertRecord();  

        }  

        long end = System.currentTimeMillis();  

          

        System.out.println("一共用时:" + (end-start)/1000.0 + "s");  

          

    }  

  

}  

 

运行结果:

[plain] 

插入成功!  

插入成功!  

插入成功!  

...  

...  

...  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

插入成功!  

一共用时:2167.19s  

 

表中已插入的记录数:

[sql] 

mysql> select count(*) from persons;  

+----------+  

| count(*) |  

+----------+  

|  1000000 |  

+----------+  

 

在没有对表的列LastName建立索引时,尝试查询:

 

[sql] 

mysql> select count(*) from persons where lastname='abc';  

+----------+  

| count(*) |  

+----------+  

|        7 |  

+----------+  

1 row in set (6.33 sec)  

 

对表列LastName建立索引:

 

[sql] 

mysql> create index my_index on persons(lastname);  

Query OK, 0 rows affected (12.44 sec)  

Records: 0  Duplicates: 0  Warnings: 0  

 

再次执行相同的查询: www.2cto.com  

 

[sql] 

mysql> select count(*) from persons where lastname='abc';  

+----------+  

| count(*) |  

+----------+  

|        7 |  

+----------+  

1 row in set (0.00 sec)  

 

当然,0.00 sec 不等于0,因为速度太快,单位太大(秒),四舍五入后导致该结果(换成毫秒可能就不为0了)。

而且每次执行的结果也不一定相同。但是通过这个小小的实验可以看出,使用索引的表比不使用索引的表要快一点,不过并不是绝对的。要不要使用索引技术要根据具体问题具体分析。如果某个表的查询次数比较多,那么就应该增加索引。但是索引会相应地使表更新速度下降(因为索引也要同时更新)。

 

创建数据库: [sql] CREATE DATABASE `sql_learn_db`; www.2cto.com 创建一个表: [sql] Create Table: CREATE TABLE `persons`...

本文由9159.com发布于编程,转载请注明出处:【9159.com】在表被创建或者删除的时候执行sql语句

关键词:

上一篇:没有了
下一篇:没有了