在本文中,我们将给您介绍关于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 主键自增)
- ibatis 自动生成键 selectkey(Oracle、MYSQL、MSSQL、SQLITE)
- ID生成(主键自增、雪花生成器)
- Linux 系统下 ThinkPHP5 链接 MsSQL
- lnmp 环境里安装 mssql 及 mssql 的 php 扩展
MSSQL 主键自增(sql server 主键自增)
可以看出每次自增为1
具体操作方案 :
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_DESCRIPTION) values (#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_DESCRIPTION) values (#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生成(主键自增、雪花生成器)
好几年前就知道时间戳+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
案例
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 扩展
小活中用到 mssql, 于是在自己 lnmp 环境中安装各 mssql 数据库
步骤如下:
源码编译安装
# 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 扩展的相关知识,请在本站搜索。
本文标签: