GVKun编程网logo

MSSQL 主键自增(sql server 主键自增)

1

在本文中,我们将给您介绍关于MSSQL主键自增的详细内容,并且为您解答sqlserver主键自增的相关问题,此外,我们还将为您提供关于ibatis自动生成键selectkey(Oracle、MYSQL

在本文中,我们将给您介绍关于MSSQL 主键自增的详细内容,并且为您解答sql server 主键自增的相关问题,此外,我们还将为您提供关于ibatis 自动生成键 selectkey(Oracle、MYSQL、MSSQL、SQLITE)、ID生成(主键自增、雪花生成器)、Linux 系统下 ThinkPHP5 链接 MsSQL、lnmp 环境里安装 mssql 及 mssql 的 php 扩展的知识。

本文目录一览:

MSSQL 主键自增(sql server 主键自增)

MSSQL 主键自增(sql server 主键自增)

MSSQL 主键自增

可以看出每次自增为1

具体操作方案 :

MSSQL 主键自增

ibatis 自动生成键 selectkey(Oracle、MYSQL、MSSQL、SQLITE)

ibatis 自动生成键 selectkey(Oracle、MYSQL、MSSQL、SQLITE)

        我们在数据库插入一条数据的时候,经常是需要返回插入这条数据的主键。但是数据库供应商之间生成主键的方式都不一样。有些是预先生成 (pre-generate) 主键的,如 Oracle 和 PostgreSQL;有些是事后生成 (post-generate) 主键的,如 MySQL 和 SQL Server。但不管是哪种方式,我们都可以用 ibatis 的节点来获取语句所产生的主键。


oracle 例子:

<insert id="insertProduct-ORACLE" parameterClass="product">  

    <selectKey resultClass="int" type="pre" keyProperty="id" >  

        SELECT STOCKIDSEQUENCE.NEXTVAL AS VALUE FROM DUAL  

    </selectKey>  

    insert into PRODUCT (PRD_ID,PRD_DESCRIPTION) values (#id#,#description#)  

</insert>

sql-server 例子:

<insert id="insertProduct-MS-SQL" parameterClass="product">  

    insert into PRODUCT (PRD_DESCRIPTIONvalues (#description#)  

    <selectKey resultClass="int" type="post" keyProperty="id" >  

        select @@IDENTITY as value  

    </selectKey>  

</insert>

mysql 例子:

<insert id="insertProduct-MYSQL" parameterClass="product">  

    insert into PRODUCT (PRD_DESCRIPTIONvalues (#description#)  

    <selectKey resultClass="int" type="post" keyProperty="id" >  

        select LAST_INSERT_ID(as value  

    </selectKey>  

</insert>

SQLite 例子:

<insert id="Create" parameterClass="Subject">
      INSERT INTO SUBJECT
      (SubjectName,QuestionCount,IsNowPaper)
      VALUES(#SubjectName#,#QuestionCount#,#IsNowPaper#)
      <selectKey resultClass="int" type="post" property="SubjectId">
        SELECT seq
        FROM sqlite_sequence
        WHERE (name = ''SUBJECT'')
      </selectKey>
    </insert>
注意:name = ''SUBJECT''中SUBJECT为表名称

 

ID生成(主键自增、雪花生成器)

ID生成(主键自增、雪花生成器)

好几年前就知道时间戳+mac地址+原子自增的方式生成主键。 新来的同事说雪花生成器,哦, 原来就是这个。cnBlog太丑了,转到这里来。

我把主键生成分为几种策略:

  • 数据库主键自增
  • 全局主键自增
  • mac地址+时间戳+原子自增

1. 数据库主键自增

我们很多时候会用到数据库。而数据表中的记录基本上都是有主键的。读书的时候,最常见的主键生成方式,就是主键自增。例如:

`record_id` int(11) NOT NULL AUTO_INCREMENT COMMENT ''记录ID,自增,全局唯一''

系统小,这个策略也是够用的了。然而当系统大了点,要考虑分布式,甚至数据库双写之类,这样的策略就不够用了。

2. 全局主键自增

其实是在1的基础上,提供一个全局的主键服务。 比如说往zookeeper等地方,获取一个id。 这种方式仅适用于低并发的情况。而且调试麻烦,不建议使用。

3. 雪花生成器(时间戳+mac地址+原子自增)

在分布式的情况下,完全避免了id生成冲突的问题。而且实现成本不高。ID的唯一性由机器的唯一性(机器mac地址)+时间戳+原子自增来保证。 最终生成一个long类型的数值,或者一个字符串。 字符串的好处是可以可以增加一些特定标识在ID中。long类型的好处是ID排序。

public static final String CLUSTER_APPID_KEY = "cluster.appid";
    private static final Charset utf8Charset = Charset.forName("utf-8");
    private static Pattern ptn = Pattern.compile("([0-9]{1})_([0-9]{1,2})");
    private static final AtomicInteger atomicId = new AtomicInteger(1);
    private static final int APP_ID_INC = 1000000;
    private static int appId = 101 * APP_ID_INC;

    static{
        //初始化appId,默认没有配置,为mac地址crc16计算值
        initAppId(null);
    }
    /*
     *根据配置的ID,做解析,配置示例:
     *appId=IdcId_HostId,
     *例如:appId=1_01,appId=1_02;appId=2_01,appId=2_02;
     * */
    public static void initAppId(String cfgAppId) {
        appId = parseAppId(cfgAppId);
        if (0 == appId) {
            appId = generateRandId();
        }
        Logger.warn("IdGenerator: APP-ID: %d", appId);
    }

    private static int parseAppId(String cfgAppId) {
        try {
            if (null == cfgAppId) {
                return 0;
            }

            Matcher matcher = ptn.matcher(cfgAppId);
            if (matcher.find()) {
                String idcId = matcher.group(1);
                int nIdcId = Integer.parseInt(idcId);
                String hostId = matcher.group(2);
                int nHostId = Integer.parseInt(hostId);
                int appId = nIdcId * 100 + nHostId;
                return appId * APP_ID_INC;
            }
        } catch (Exception e) {
            //ignore
        }
        return 0;
    }

    private static int generateRandId() {
        String mac = UUID.randomUUID().toString();
        try {
            String tmpMac = getMacAddress();
            if (null != tmpMac) {
                mac = tmpMac;
            }
        } catch (Exception e) {
            //ignore
        }
        int tmpRst = getChecksum(mac);
        if (tmpRst < 999 && tmpRst > 0) {
            return tmpRst * APP_ID_INC;
        }
        //大于999,取余数
        int mod = tmpRst % 999;
        if (mod == 0) {
            //不允许取0
            mod = 1;
        }
        return mod * APP_ID_INC;
    }

    private static String getMacAddress() throws Exception {
        Enumeration<NetworkInterface> ni = NetworkInterface.getNetworkInterfaces();
        while (ni.hasMoreElements()) {
            NetworkInterface netI = ni.nextElement();
            if (null == netI) {
                continue;
            }
            byte[] macBytes = netI.getHardwareAddress();
            if (netI.isUp() && !netI.isLoopback() && null != macBytes && macBytes.length == 6) {
                StringBuilder sb = new StringBuilder();
                for (int i = 0, nLen = macBytes.length; i < nLen; i++) {
                    byte b = macBytes[i];
                    //与11110000作按位与运算以便读取当前字节高4位  
                    sb.append(Integer.toHexString((b & 240) >> 4));
                    //与00001111作按位与运算以便读取当前字节低4位  
                    sb.append(Integer.toHexString(b & 15));
                    if (i < nLen - 1) {
                        sb.append("-");
                    }
                }
                return sb.toString().toUpperCase();
            }
        }
        return null;
    }

    /**
     * 获取对应的CRC16校验码
     * @param input 待校验的字符串
     * @return 返回对应的校验和
     */
    private static int getChecksum(String input) {
        if (null == input) {
            return 0;
        }
        byte[] data = input.getBytes(utf8Charset);
        CRC16 crc16 = new CRC16();
        for (byte b : data) {
            crc16.update(b);
        }
        return crc16.value;
    }

    /**
     * 获取随机数,加大随机数位数,是为了防止高并发,且单个并发中存在循环获取ID的场景
     * 如果您的应用并发有200以上,且每个并发中都存在循环调用获取ID的场景,可能会发生ID冲突
     * 对应的解决方法是:在循环逻辑中加入休眠1-5ms的逻辑
     * @return
     */
    private static int getRandNum() {
        int num = atomicId.getAndIncrement();
        if (num >= 999999) {
            atomicId.set(0);
            return atomicId.getAndIncrement();
        }
        return num;
    }
    
    public static Long getId() {
       
        long id = getBasicId();
        return Long.valueOf(id);
    }

    public static long getBasicId() {
        return (System.currentTimeMillis() / 1000) * 1000000000 + appId + getRandNum();
    }

补充

建议优化为: 时间戳+mac地址+应用实例id+原子自增。 大规模集群的情况下有可能单机多实例。单机多应用实例增加实例的id做区分。

我以前在cnblog写的主键自增

Linux 系统下 ThinkPHP5 链接 MsSQL

Linux 系统下 ThinkPHP5 链接 MsSQL

案例

CentOS6.8 系统 ThinkPHP5 链接 MsSQL 数据库。

分析

ThinkPHP5 提供了 Mysql、Pgsql、Sqlite 和 Sqlsrv 四种数据库驱动。Window 系统下有现成的 php_sqlsrv.dll 扩展可用,但 Linux 系统中没有 (本人没有找到)。

尝试 1 未成功,写来以备其它用途

安装 freetds

wget ftp://ftp.freetds.org/pub/freetds/stable/freetds-patched.tar.gz
tar -zxvf freetds-patched.tar.gz
cd freetds-*
./configure --prefix=/usr/local/freetds --with-tdsver=auto --enable-msdblib --with-gnu-ld --enable-shared --enable-static
make && make install

安装 mssql

wget http://cn2.php.net/distributions/php-5.6.22.tar.gz
tar -zxvf php-5.6.22.tar.gz
cd php-*/ext/mssql
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config --with-mssql=/usr/local/freetds
make && make install 

修改 php.ini,添加如下配置 (路径请根据环境不同而定)

extension="/usr/local/php/lib/php/extensions/no-debug-non-zts-20131226/mssql.so"

修改 ThinkPHP5 配置文件 database.php

// 数据库类型
''type''           => ''sqlsrv'',
// 服务器地址
''hostname''       => ''192.168.1.210'',
// 数据库名
''database''       => ''dbname'',
// 用户名
''username''       => ''sa'',
// 密码
''password''       => ''123456'',
// 端口
''hostport''       => ''1433'',

测试

这种方式在 ThinkPHP 中是行不通的,在其它应用环境可以。

尝试 2 成功

安装 freetds

wget ftp://ftp.freetds.org/pub/freetds/stable/freetds-patched.tar.gz
tar -zxvf freetds-patched.tar.gz
cd freetds-*
./configure --prefix=/usr/local/freetds --with-tdsver=auto --enable-msdblib --with-gnu-ld --enable-shared --enable-static
make && make install

安装 pdo_dblib

wget http://cn2.php.net/distributions/php-5.6.22.tar.gz
tar -zxvf php-5.6.22.tar.gz
cd php-*/ext/pdo_dblib
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config --with-pdo-dblib=/usr/local/freetds
make && make install 

修改 php.ini,添加如下配置 (路径请根据环境不同而定)

extension="/usr/local/php/lib/php/extensions/no-debug-non-zts-20131226/pdo_dblib.so"

修改 ThinkPHP5 配置文件 database.php

// 数据库类型
''type''           => ''dblib'',
// 服务器地址
''hostname''       => ''192.168.1.210'',
// 数据库名
''database''       => ''dbname'',
// 用户名
''username''       => ''sa'',
// 密码
''password''       => ''123456'',
// 端口
''hostport''       => ''1433'',

下载 ThinkPHP 数据库驱动 Dblib 文件

将文件拷贝到 thinkphp/library/think/db 目录。

测试

成功。

lnmp 环境里安装 mssql 及 mssql 的 php 扩展

lnmp 环境里安装 mssql 及 mssql 的 php 扩展

小活中用到 mssql, 于是在自己 lnmp 环境中安装各 mssql 数据库

步骤如下: 

源码编译安装

(1)下载 freetds-stable-0.91 源码: http://download.csdn.net/download/xhu_eternalcc/7457555(花了 4 积分,没有积分的找我要,微信 zmd1047773569)
          上传到根目录下的 download 文件中
(2)编译安装:
   # cd /download

           # tar zxvf freetds-stable.tgz(解压,)

 

   # cd freetds-0.91

   # 编译

            # ./configure --prefix=/usr/local/freetds --with-tdsver=8.0 --enable-msdblib

            # make

            # make install

            参数解释:

            安装 freetds 到目录 /usr/local/freetds:--prefix=/usr/local/freetds

            支持 MSSQL2000:--with-tdsver=8.0 --enable-msdblib

 

配置 FreeTds 的库文件

将 freetds 的库文件所在路径配置到 LD_LIBRARY_PATH 参数中:

$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/localfreetds/lib/:

或者直接把 etc/bashrc 的文件 bashrc 直接填写上  LD_LIBRARY_PATH=/usr/localfreetds/lib:$LD_LIBRARY_PATH

这么作的目的是为了避免加载 FreeTds 库文件加载不上的情况。

 

 

php 里安装 php-mssql 扩展:

cd /download (把php-mssql扩展下载到download目录里)
wget http://cn2.php.net/distributions/php-5.6.30.tar.gz (下载扩展文件,这里要根据你环境中运行的php版本选择对应的扩展版本下载,我这里php是5.6.30的 所以php-mssql扩展下载对应的版本) tar -zxvf php-5.6.30.tar.gz cd /php-5.6.30/ext/mssql
 /usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config --with-mssql=/usr/local/freetds/ 

make
&& make install

编译安装后的结果 如下图

 

同时 mssql.so 也在 php 扩展文件下生成 (如下图)

 

 

 

 把 extension="/usr/local/php/lib/php/extensions/no-debug-non-zts-20131226/mssql.so"  添加到 usr/local/php/lib/php.ini 中

 引用扩展后,重启 web 服务,通过 phpinfo 查看扩展 mssql 是否开启成功

重启 php   /usr/local/php/sbin/php-fpm reload  

重启 nginx  进入 nginx 可执行目录 sbin 下,输入命令./nginx -s reload 即可(或者 /application/nginx/sbin/nginx -s reload)

 

 

 

今天关于MSSQL 主键自增sql server 主键自增的讲解已经结束,谢谢您的阅读,如果想了解更多关于ibatis 自动生成键 selectkey(Oracle、MYSQL、MSSQL、SQLITE)、ID生成(主键自增、雪花生成器)、Linux 系统下 ThinkPHP5 链接 MsSQL、lnmp 环境里安装 mssql 及 mssql 的 php 扩展的相关知识,请在本站搜索。

本文标签: