首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

Python学习-基础知识-2

目录 Python基础知识2 一、二进制 二、文字编码-基础 为什么要有文字编码? 有哪些编码格式? 如何解决不同国家不兼容的编码格式? unicode编码格式的缺点 如何既能全球通用还可以规避unicode的缺点? python3的编码格式是什么样的? 三、浮点数 四、列表 如何理解列表? 列表的操作有哪些? 深浅复制问题 五、字符串 什么是字符串? 字符串的常用方法 使用r取消字符串转义 六、元组 元组和列表有什么区别? 七、哈希 八、字典 什么是字典? 字典常用操作 九、集合 什么是集合? 集合基本操作 集合分类计算 十、文件编码--进阶 十一、几个技术问题 if 条件语句判断 字典的两种循环方法对比 while...else... Python基础知识2 标签:python 目录: 一、二进制 计算机内部使用二进制表示数据。1位二进制可以代表2种状态,n位二进制可以表示2^n种状态,一般使用如下图示来计算一个字节的二进制和十进制互转: 128 64 32 16 8 4 2 1 256 1 1 1 1 1 1 1 1 78 0 1 0 0 1 1 1 0 33 0 0 1 0 0 0 0 1 6 0 0 0 0 0 1 1 0 二、文字编码-基础 为什么要有文字编码? 不论是文字、图片、视频还是其他类型的数据,在计算机内部都是以二进制的形式存储和表示。对于文字类型的数据,二进制需要通过文字编码表的映射关系,将二进制数据转换为对应的文字。文字编码表预先收录了字形和二进制数据的对应关系。但不同的国家因文字不同,所以产生了不同的编码表,编码表也叫作编码格式。 有哪些编码格式? 因不同国家的文字不同,各国都编写了适合本国语言的编码格式。如GBK是中国的编码格式,ASCII是美国的编码格式,SHIFT_JIS是日本的编码格式等等。不同的编码格式给出了不同的二进制和字形的对应关系标准,所以不同编码格式之间不能混用,否则会出现乱码。 如何解决不同国家不兼容的编码格式? 正因为编码格式互相不兼容,国际标准组织才出面编写了一个全球各国通用的unicode编码格式,此编码格式将全世界的语言都囊括进去,不论是哪一个国家,只要使用unicode进行编码,输出的文件都可以在全球通用,所以unicode也称为:万国码。(当然,读取的时候也要使用unicode编码进行读取) unicode编码格式的缺点 但是,unicode编码格式要求一个字符至少对应2个字节的二进制数据,这就导致对于编码长度小于2个字节的语言比如英文来说,存储空间加倍,不但影响存储,还影响传输效率。 如何既能全球通用还可以规避unicode的缺点? 此时UTF-8编码格式应运而生,UTF-8在unicode基础上,使用可变长编码的方法,使用1-4个字节来表示一个字符,优先使用1字节,不够的话再增加1字节,以此类推。通过变长的方式用于优化unicode在存储和传输时带来的资源浪费。 python3的编码格式是什么样的? 简单来说,python3在内存中操作字符串时的编码格式统一是unicode,而在读写文件时使用的编码格式默认是UTF-8。 三、浮点数 python中的浮点数包括:有限小数(如:1.2)和无限循环小数(如:1/3)。 python中的浮点数精度最长只有小数点后16位,可以使用decimal模块来提高精度。使用python3的/运算得到的结果就是浮点数。此外,浮点数还用于科学计数法,如1000000的科学计数法写法是:1.0E6。 当超出浮点数当前精度的时候会发生四舍五入的操作。 四、列表 如何理解列表? 列表可以简单的被理解成一个存储容器。此容器可以存放不同种类的对象,可以新增一个对象、删除一个对象、或者替换一个对象。列表类似于数组,只不过python的列表是动态的,不仅可以动态扩展和缩小长度,还可以存放不同的数据类型。列表使用如下方式声明: li = [0,1,2,3,4] 或者 li = list(range(5)) 列表的操作有哪些? 1. 查询 li[0]或者li[-1] # 通过下标索引对象值,不能超出下标范围 li.index('a') # 通过对象值查找对应下标,不存在的对象会导致此函数报错ValueError li.count('a') # 得到列表中'a'值出现的次数 2. 增加 li.append(20) # 在列表末尾追加元素 li.insert(0, 20) # 在列表下标0出插入20,这会导致元素右侧统一右移一个单位 3. 修改 li[0] = 20 # 直接修改第一个元素的值为20 li[:3] = [1,2,3] # 将列表前三个元素批量修改 4. 删除 li.remove(23) # 根据元素值删除元素,不存在会报错ValueError li.pop(0) # 根据元素下标删除元素,不给于参数则默认-1 del li[1] # 使用通用删除关键字del del li[1:5] # 使用del批量删除 5. 切片 li = [1,2,3,4,5] L = li[:3] # L的值是[1,2,3],切片含首不含尾 L = li[:] # 将li列表进行浅复制赋予L L = li[::-1] # 将li列表倒序后浅复制赋予L 6. 更新/扩展 list_a.extend(list_b) # 将b的值更新至a list_a = [1,2] list_b = [2,3] list_a.extend(list_b) # a的值是[1,2,3],b保持不变 7. 拼接 list_a = [1,2] list_b = [2,3] list_c = list_a + list_c # c的值是[1,2,3],a和b保持不变 8. 排序 li.sort() # 在原始列表上修改,排序默认方式是升序 li.reverse() # 让列表倒序 9. 循环 for i in li: print(i) 10. 清空/复制 li.clear() list_b = list_a.copy() # 等价于list_b = list_a[:] 深浅复制问题 因为列表是可变对象,即列表中的元素是可以改变的,所以在复制列表的时候,如果使用简单的复制(即浅复制),遇到嵌套的小列表时就会出现问题。为了规避可变对象在修改值时的安全问题,对于可变对象的复制,建议使用深复制。深复制的使用方式如下: import copy list1 = [1,2,3,[4,5],6] list2 = copy.deepcopy(list1) list1[-2][-1] = 'abc' print(list1) print(list2) 结果是: [1, 2, 3, [4, 'abc'], 6] [1, 2, 3, [4, 5], 6] 五、字符串 什么是字符串? 字符串就是一串字符序列,字符串在计算机中也是二进制数据,这些二进制数据通过编码格式显示成对应的字形,即字符串。字符串是不可变对象,一旦被创建就无法被修改。 字符串的常用方法 1.判断是否是数字字符串 str.isdigit() s = '123' s.isdigit() # 值是True s = '123b' s.isdigit() # 值是False 2. 替换字符 str2 = str1.replace(old, new) # 返回一个新字符串 s1 = 'aaahello,world' s2 = s1.replace('a', 'A') print(s1) print(s2) 结果: aaahello,world AAAhello,world 3. 定位字符 i = str.index(char) # 不存在会报错 i = str.find(char) # 不存在返回-1 s1 = 'aaahello world' print(s1.index('a')) print(s1.index('b')) print(s1.find('a')) print(s1.find('b')) 结果: 0 报错ValueError 0 -1 4. 字符计数 count = str.count(char) # 查找字符串中char字符的个数 s1 = 'aaahello world' print(s1.count('a')) 结果: 3 5. 处理首尾空格 str2 = str1.strip() # 返回新字符串,删除首尾空格 s1 = ' hello world' print(s1) print(s1.strip()) 结果: hello world hello world 6. 处理banner展示条 str2 = str1.center(len, char) # 使用char填充字符串长度到len s1 = 'student info' print(s1.center(20, '*')) print(s1.center(20, '-')) print(s1.center(20, '+')) 结果: ****student info**** ----student info---- ++++student info++++ 7. 分割字符串产生列表 list = str.split(char) # 根据char字符分割字符串成列表,默认cahr是空格 s1 = 'student!info!xiaoming' li = s1.split('!') print(type(li)) print(li) 结果: <class 'list'> ['student', 'info', 'xiaoming'] 8. 拼接字符串列表成更长字符串 str = char.join(list) # 根据char字符连接list里的所有字符串成为更长的字符串 li = ['student', 'info', 'xiaoming'] s1 = '+'.join(li) print(type(s1)) print(s1) 结果: <class 'str'> student+info+xiaoming 9. 字符串格式化输出 str2 = str1.format(*args, **kw) # 根据args和kw来对应赋值 result = 'name:{name}, age:{age}, a {0},a {1}'.format('apple', 'bananer', name='xiaoming', age=26) print(result) 结果: name:xiaoming, age:26, a apple,a bananer 10. 判断字符串开头和结尾 bool = str.startwith/endwith(char) # 判断是否以char开头或结尾 s1 = 'hello' s2 = 'world' print(s1.startswith('h')) print(s2.endswith('d')) 结果: True True 11. 改变字符串大小写 str2 = str1.upper/lower() # 设置大小写 s1 = 'hello world' print(s1.upper()) 结果: HELLO WORLD 使用r取消字符串转义 在字符串前面增加一个r可以取消此字符串在print过程中的转义功能,从而打印出字符串字面量。 s1 = '\ta\nbc' print(s1) s2 = r'\tabc\n' print(s2) 结果: a bc \tabc\n 六、元组 元组和列表有什么区别? 元组可以认为是只读列表,元组的操作大部分和列表一致,只不过一旦定义完毕之后就不能修改元组元素的值。 但是,如果元组元素是一个可变对象比如列表,则可以修改此列表中的值,这并不违反元组的规则因为列表自身这个容器的内存地址并没有变化。 tu = (1,2,[3,4]) # tu[0] = 10 # 这条语句会报错 tu[-1].append(5) print(tu) 结果是: (1, 2, [3, 4, 5]) 七、哈希 哈希函数用于将任意长度的输入通过算法计算得到固定长度的输出,这个输出也叫哈希值。 哈希算法是根据输入值的特征计算的,所以如果输入值不停变化,则输出也会不稳定,这就要求输入的是不可变对象。 因为哈希算法的原因,可能会出现不同的输入值有同样的输出值,这就发生了哈希冲突,所以想通过输出来反推唯一的输入是不合理的。 数据中保存的用户密码都是密文。 使用哈希的程序一定要有处理冲突的模块。 八、字典 什么是字典? 字典在某种角度上和列表很类似,都可以被认为是存储工具,保存各种数据类型对象。不过列表是通过下标索引,而字典是通过key来索引。另外,列表是有序的,而字典是无序的,因为字典的key涉及到哈希算法的计算。 数据类型 是否有序 索引值 作用 是否可变对象 使用方式 列表 有序 下标,从0开始 存储其他对象地址 是 li[0],li[-1] 字典 无序 key值,不可变对象 存储其他对象地址 是 dic[key] 字典常用操作 1. 增加 字典没有追加的函数,增加一个key-value的方式是直接: dic['name'] = 'xiaoming' 如果dic中已经存在'name'的key,则会使用'xiaoming'来覆盖原有的value 2. 修改 字典的修改直接是: dic['name'] = new_value 将新的值覆盖原有值 3. 查找 方法1:print(dic['name']) 如果dic没有'name'的key,则会报错 方法2:print(dic.get('name', 'not found!') 如果dic没有'name'的key,则会返回'not found!',默认第二参数是None,可以不填写 4. 删除 方法1:del dic['name'] 如果dic没有'name'的key,则会报错 方法2:dic.pop('name', 'not found!') 如果dic没有'name'的key,则会返回'not found!',第二参数没有默认值,必须手工输入否则会报错 5. 清空/复制 dic.clear() dic2 = dic1.copy() # 浅复制 6. 设置默认 dic.setdefault('name', 'xiaoming') 首先,dic会查找自身是否有'name',如果有返回原有value值。如果没有,就新增这个key-value并返回新value值。 7. 更新 dic1.update(dic2) 使用dic2来更新dic1,有则覆盖,无则新增。 dic1 = { 'a': 1, 'b': 2, 'x': 3,{'a': 1, 'b': 2, 'x': 100, 'y': 200} } dic2 = { 'b': 2, 'x': 100, 'y': 200, } dic1.update(dic2) print(dic1) 结果是: {'a': 1, 'b': 2, 'x': 100, 'y': 200 } 8. fromkeys 为一系列key设置统一的value值,并返回此字典。比如要为3个房地产楼盘设置统一价格: dic = dict.fromkeys(['万科', '阳光城', '融信'], 2000) print(dic) 结果是: {'万科': 2000, '阳光城': 2000, '融信': 2000} 9. 循环获取keys、values、items for key in dic.keys() for value in dic.values() for item in dic.items() 九、集合 什么是集合? 集合一般用于分类计算。集合中的元素都是唯一的,不会有重复。集合是无序的,集合是可变对象,但是集合内的元素必须是不可变对象。因为集合一般用于分类计算,是站在集合维度的,所以集合并不支持s[0]这种方式来访问元素。 集合基本操作 s = {1,2,3,4,5} print(s.pop()) # 随机删除一个元素 s.add(50) s.add(60) print(s) s.discard(100) # 删除元素,不存在不会报错 # s.remove(100) # 100不存在就会报错 s2 = {100,200,300} s.update(s2) # 两个集合合并,其实就是并集 print(s) s.clear() # 清空集合元素 print(s) 结果是: 1 {2, 3, 4, 5, 50, 60} {2, 3, 4, 5, 100, 200, 300, 50, 60} set() # 代表空集合 集合分类计算 s1 = {11,22,33} s2 = {22,33,44} print('交集是:', s1 & s2) # 交集是: {33, 22} print('s1 对于 s2 的差集是:', s1 - s2) # s1 对于 s2 的差集是: {11} print('s2 对于 s1 的差集是:', s2 - s1) # s2 对于 s1 的差集是: {44} print('并集是:', s1 | s2) # 并集是: {33, 11, 44, 22} print('对称差集是:', s1 ^ s2) # 对称差集是: {11, 44} print('s1是s2的超集吗?', s1.issuperset(s2), s1 > s2) # s1是s2的超集吗? False False print('s1是s2的子集吗?', s1.issubset(s2), s1 < s2) # s1是s2的子集吗? False False print('23在不在是s1中?', 23 in s1) # 23在不在是s1中? False print('s1 和 s2 是不是 不相交?', s1.isdisjoint(s2)) # s1 和 s2 是不是 不相交? False 十、文件编码--进阶 这里从:python3读取文件abc.txt,执行文件中的代码并在命令行展现内容的整个过程来理解各环节的编码问题。 文件准备 # abc.txt str1 = '中国' print(str1) 环境准备 python环境:python3.6.1 os环境:windows 10 abc.txt是使用pycharm编辑的,pycharm的编码设置为UTF-8 开始 我们登录windows操作系统,windows操作系统默认的编码格式是GBK,windows中有一个cmd命令行,此命令行的编码格式继承了操作系统的格式,也是GBK。 打开pycharm,默认pycharm在安装完毕后的编码格式是GBK,可以通过设置修改为UTF-8。 在pycharm中创建文件abc.txt,在此文件中写入: str1 = '中国' print(str1) 注意,此时abc.txt文件中的str1的编码格式是UTF-8,即编辑器pycharm是什么格式,则编写的文件就是什么编码格式。 使用Crtl+s保存此文件到硬盘。 单独在cmd中打开python解释器,进入交互环境,在交互环境中,我们可以输入: s1 = 'hello world' s2 = '你好 世界' 不论你输入的是什么字符串,不论是中文还是英文,此时在python3交互环境中的编码格式都是统一的unicode。 退出python3交互环境,在cmd命令中通过命令启动python3解释器执行abc.txt文件:python abc.txt 第7步其实有很多小环节: python3会使用默认的读写文件的编码格式对abc.txt文件进行解释。python3默认读写编码格式是UTF-8,而此文件恰好也是以UTF-8格式保存在硬盘上的,所以python3可以正确的对此文件进行编码。 python3通过UTF-8读写文件编码对此文件进行解释,将UTF-8的文件内容转换成unicode格式的字符串保留在内存中。 python3解释器执行unicode的保存在内存中的代码,设置一个str1变量,创建一个unicode格式的'中国' python3执行print函数,此时str1依然是unicode格式 print函数被执行,str1的'中国'会被打印到cmd中 cmd命令行接收到一个以unicode编码的字符串,虽然cmd默认是GBK编码,但是cmd可以认识GBK和unicode,所以可以根据unicode编码规则打印出此字符串的字形:'中国' 总之,有如下几个环节是需要编码的: python3解释器内部编码,也就是在内存中的编码格式,就是unicode python3解释器去读取文件时使用的编码格式,默认是UTF-8,会按照你在文件头部指定的# coding: xxx来设定,不设定的话就是UTF-8 文件自身也有一个编码格式,此编码格式来源于编辑此文件的编辑器 编辑器的编码格式继承了操作系统的编码格式,mac/Linux是UTF-8,windows是GBK,此外,cmd和shell也继承了操作系统的编码格式 十一、几个技术问题 if 条件语句判断 a = [1] if a: print('true') else: print('false') 这里的if条件是判断成立的,但是如下两者却是false: a == True a is True 为什么? 首先,a和True不能用is比较,因为是肯定不同的两个对象内存地址。也不能用==比较因为是不同的数据类型,值是肯定不同的。其次,if a这个语句等价于:if boo(a),bool(a)的结果是True,所以可以判断成立。 字典的两种循环方法对比 dic = { 'a': 1, 'b': 2, 'c': 3, } for key in dic.keys(): print(key, dic[key]) for key, value in dic.items(): print(key, value) 哪一种循环的性能更好? 尝试过两种办法: 两种循环各循环100次,计算运行时间,发现是下面那种时间短。 扩大dic的数据量到100万个项目,两种循环各执行1次,发现上面那种时间短。 目前还不知道确切分析的方法,后续补充。 while...else... 用处:需要判断while是否完全正常执行完毕时 i = 0 while i < 10: print(i) i += 1 else: print('循环正常执行完毕,没有被break或者return打断')

优秀的个人博客,低调大师

docker重点 学习以及指令资料

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34173549/article/details/80597552 --name 名称 -it -i 容器输入终端保持打开, -t开一个伪终端 ip ad li 查看网段 docker attach id 获取docker 有些容器进入不成功 后台运行 ctrl p + ctrl q 获取容器pid nsenter nsenter --target 4497 --mount --uts --ipc --net --pid root /usr/share/nginx/html 91 映像端口 80 容器被映像的端口 -h 指定主机名 -v 数据卷 docker run -it --name volume-test1 -h centos -v /datacentos docker inspect -f "{{.Volumes}}"volume-test1 docker日志如何存储 只读格式 useradd -s /sbin/nologin -M www 前台运行 docker commit -m "my nginx" c85374823499rainyday/my-ngnix:v1 #This is My first Dockerfile # Version 1.0 #Author : Rainyday From centos #MAINTAINER MAINTAINER Rainyday #ADD ADD pcre-8.42.tar.gz /usr/local/src ADD nginx-1.13.12.tar.gz /usr/local/src #RUN RUN yum install -y wget gcc gcc-c++ make openssl-devel RUN useradd -s /sbin/nologin -M www #WORKDIR WORKDIR /usr/local/src/nginx-1.13.12 RUN ./configure --prefix=/usr/local/nginx --user=www--with-http_ssl_module --with-http_stub_status_module--with-pcre=/usr/local/src/pcre-8.42 && make &&make install RUN echo "daemon off;" >>/usr/local/nginx/conf/nginx.conf ENV PATH /usr/local/nginx/sbin:$PATH EXPOSE 80 CMD ["nginx"] 资源限制 cgroup http://mirrors.aliyun.com/repo/ wget http://mirrors.aliyun.com/repo/epel-6.repo docker build -t stress . docker images docker run -it --rm -c 512 stress --cpu 1 指定cpu大小 docker run -it --rm stress --cpu 1 指定cpu docker run -it --rm --cpuset-cpus=0 stress --cpu 1 指定占用几个cpu docker exec id docker run -it --rm -m 128m stress --v m 1 --vm-bytes 120m --vm-hang 0 测压大于两倍关掉 cpu -c --cpu-set 内存 -m docker 网络模式 docker run -d -p 5001:5000 registry docker push localhost:5001/test/e:v1 docker tag d1fd7d86a825 47.106.154.105:5001/test/es:v1 echo '{"insecure-registries":["47.106.154.105:5001"] }' >/etc/docker/daemon.json docker pull 47.106.154.105:5001/test/e:v1 shipyard -H tcp:0.0.0.0:235 -H unix:///var:/run/docker.sock docker run -it -d --name shipyard-rethinkdb-data--entrypoint /bin/bash shipyard/rethinkdb -l

优秀的个人博客,低调大师

python学习-基础知识-1

1、计算机历史 计算机使用高低电压的两种状态来描述信息。计算机可以理解的只有二进制数据即010100011....,1个比特位可以表示的状态只有2种,n个比特位可以表示的状态有2的n次方种。 所以如果想要描述天气状态:天晴、下雨、刮风、下雪、霜冻,则需要使用3个比特位。 2、编程语言历史 计算机只能理解二进制数据,二进制数据中蕴含了很多指令、操作、数据,计算机通过cpu直接运行二进制代码执行不同的功能,二进制代码被称为机器语言。 但是机器语言(二进制代码)对于人类而言可读性太差、编写太困难,所以人类需要使用适合自身的语言来编程以操作计算机。 一开始,人类将机器语言中的代码进行分类、标记,把蕴含操作行为、蕴含数据的二进制代码使用英语单词标记,形成了汇编语言。汇编语言的模式是:操作行为+被操作数。 操作行为和被操作数都使用英语单词代替了一串010101的二进制代码,这样人类只需要编写汇编语言,再将汇编语言通过之前的映射关系转换成二进制即可。 通过汇编语言,人类即可以方便的编写代码,又可以通过转化得到对应的二进制代码让计算机运行。 但是,汇编语言依然可读性较差、编写也不是非常的方便,要实现一个简单的功能需要非常多的汇编代码,代码冗余性依然很高。 于是,人类模仿汇编和二进制的对应关系,将高级语言和汇编又对应起来,这时候人类就只需要编写高级语言,再通过编译器将高级语言转换成汇编语言或者直接转换成二进制代码。 高级语言的代码非常接近人类的英语,所以使用起来很方便。 因语法规则、语义的不同,高级语言分为很多种,如:python,java、c、c++、JavaScript,ruby等等。 3、编译型高级语言/解释性高级语言 高级语言接近人类英语,编写的代码可读性也很强,但是计算机是无法直接理解和执行源代码的,因为计算机只认识二进制代码,所以不论是哪一种高级语言,都需要将源代码转换成二进制代码后才能被计算机执行。 在转换过程中,有2种不同的情况: 1、编译型 编译型高级语言,在程序执行之前,需要提前将源代码通过编译器转换成目标文件(二进制代码),然后计算机直接执行目标文件。 优点:计算机执行效率高、速度快 缺点: 如果程序需要修改,必须修改源代码并再次编译,修改不方便 一旦编译完成,目标文件就只能在当前操作系统和cpu架构上运行,无法在其他平台使用,除非重新编译 举例:c、c++、c# 2、解释型 解释型高级语言,由解释器实时读取源代码并编译成二级制代码交由计算机执行。 优点: 程序的修改直接操作源文件即可,修改方便 只要计算机安装了对应平台的解释器,源代码就可以被执行,即一份源代码可以在不同平台运行,平台兼容性好 缺点: 因为需要实时编译,所以运行效率低、速度较慢 需要一个匹配版本和平台的解释器与源代码共同工作 举例:python、java、ruby 4、python版本 python有2个相互不兼容的大版本,版本2最高是2.7,版本3截止20180603最高是3.6.5。版本2官方宣布将会维护到2020年,建议现在选择版本3编码。 5、python解释器 解释器也是一种程序,功能是将python源代码翻译成机器语言。解释器可以使用多种语言编写,有如下几种: cpython,官方发布的解释器,使用c语言编写 ipython,在cpython基础上套了一个壳,提高用户交互性 pypy,据说使用jit技术动态实时编译使得代码运行速度更快,但是目前暂不成熟 jpython和icronpython,使用java和.net编写,一般不使用 6、python文件执行 两种方式执行python文件,一种是启动解释器并将python源文件作为参数,解释器读取文件中代码。一种是启动解释器,在交互环境编写代码执行。 7、变量 1、变量存在的原因 用于保存阶段性计算的结果,同时变量用于描述程序中的一些数据,良好的变量命名和使用会增加代码的可读性。 2、变量命名规范 变量名可以是数字、字母、下划线的任意组合,注意:不可使用除了下划线之外的特殊字符 变量名开头不能是数字 变量名不能和python预定义的关键字重名 注意:python竟然可以使用中文作为变量名! 3、变量定义语法 age = 26 定义一个变量,它的名字是age,此变量指向内存中的一个对象,此对象值是26 8、常量 常量的命名规范和变量一样,不过常量的命名约定俗成的是全大写。 常量用于保存基本不变的数据,python没有提供类似c语言的const关键字来强制规定常量的不可变性,所以python中的常量是约定俗成的不可变。 9、python安装 www.python.org官网下载最新版本3.6.5,根据电脑配置选择32或者64位,安装的时候选择add to path并自定义安装位置和其他高级选项,安装完成可以直接shell进入python解释器。 10、输入/输出 python中通过input函数提供shell输入,通过print函数提供shell打印。 input函数会阻塞程序执行直到获取shell输入值 11、注释 不论哪一种高级语言,我们在编码的时候都是将脑海中的思路、信息、步骤简化成实际的代码。将大脑中的信息转换成实际代码的时候,会有很大的信息量丢失,即代码所表达的信息量是很少的。 所以单独的代码无法还原编码时的全部信息量,此时我们就需要使用注释来弥补代码缺失的信息量。优秀的注释+代码可以提供很高的可读性,也方便后续代码使用和维护。 注释有几个需要遵守的规范: 1、注释的内容应该保持与代码的强一致性,注释应该精简、准确的表达代码的含义、编码背景等 2、可以使用中文或者英文 3、注意注释的使用量,在适当且必要的地方使用注释,如:重要流程节点、复杂代码块解释等 12、数据类型 计算机只认识二进制,对于计算机而言,数据没有类别,全部都是010101010... 但是对于人类而言,人类世界中的数据、信息是五花八门的,我们编码的过程其实就是在计算机世界中对现实世界进行建模的过程,所以我们需要对人类世界的数据划分类别。 基础的数据类型有:数字(整数+小数)、字符串、布尔值 我们使用int来表示整数类型、float表示小数类型 我们使用str表示字符串类型 我们使用bool表示布尔值类型 数字类型用于计算、字符串类型用于表示信息、布尔类型用于判断 13、字符串格式化输出 所谓格式化输出,其实就是在编码过程中定义展示模板,在模板中通过占位符代表后续有对应数据填充在此。 占位符: %d 整数类型 %f 小数类型 %s 字符串类型(%s是万能匹配,即任意数据类型都可以填充到%s占位符中) %r 原格式(将数据的原始格式存放到%r占位符中,如字符串的原格式就包含引号) 14、运算符 算数运算符 + - * / (注意,/ 除法运算符得到的商可以是小数,即5/2 = 2.5) // % (地板除得到的结果是商的整数部分,如5//2 = 2。取模得到的结果是未整除的结果,如5%2 = 1,对2取模可以判断奇偶。) ** (幂运算,5**2 = 25) 比较运算符 == > < >= <= != (==表示的是两边对象的值是否相等,python3中使用!=表示不等于,不再使用<>) 赋值运算符 = (赋值) += -= *= /= //= %= **= (在原有值的基础上做运算,并赋值给原有变量,如a = 5, a %= 2,此时a = 1) 逻辑运算符 and or no (逻辑判断会使用短路判断,所以:使用and的时候,概率小的放前面。使用or的时候,概率大的放前面。) 15、流程控制-分支 程序默认是自上而下没有分支的执行代码。很多时候我们需要通过判断程序运行中间的某一种状态、情况、值,来决策程序下一步该执行哪些代码。 通过分支提供多条执行路线,分支有双分支、多分支。 之所以可以划分多种分支是因为可能出现多种不同条件,而这些条件的概率和应该为1。 分支需要特别注意条件判断的逻辑性,多种条件只会执行其中一个条件,条件之间是相互对立的。 通过if elif elif else来提供多分支,通过条件的布尔值结果判断条件是否成立。 注意:条件判断应该把概率大的放在前面,概率小的放后面,对于无法明确具体判断条件的可以放在else统一匹配。另外,判断input的返回值的时候注意,input返回值一定是字符串。 16、流程控制-循环-while while关键字后面的语义是:判断条件是否成立?成立的话执行一次循环体然后再次判断条件是否成立。不成立的话跳过此循环体执行后续代码。 因为循环代码有导致死循环的风险,所以任何一个循环定义,都需要预先设计循环跳出条件。循环可以在循环体中通过break跳出,或者通过while条件判断不成立跳过。(当然,也可以在循环体中exit) 通过continue可以提前结束当前循环,直接开始下一次的循环while判断,注意:continue应用于跳过后续本应该执行的代码。 因为continue可以跳过后续本应该执行的代码,而后续执行代码中可能包含循环跳出的设置如:i += 1。所以continue的使用会有死循环风险,需要单独处理循环跳出问题。 17、while...else... 据说使用while后面的else,如果while正常执行完毕,则执行else。如果while没有正常执行完毕如被break打断,则不会执行else。可以使用else是否执行来判断循环是否正常执行完毕,我觉得这并不合理,考虑下述代码: 1 i = 11 2 while i < 10: 3 print('i is:', i) 4 i += 1 5 if i == 3: 6 break 7 else: 8 print('循环正常执行完毕') 9 10 # 循环没有正常执行完毕,实际上循环根本就没执行,else也被执行了。所以else被用于判断 11 # while是否正常执行我觉得并不合理。 18、while的使用 思考如下练习: # 使用while,完成以下图形的输出 # # * # * * # * * * # * * * * # * * * * * # * * * * # * * * # * * # * 1 star = 1 2 most_star = 5 3 while star <= most_star: 4 print(' *' * star) 5 if star == most_star: 6 while most_star > 0: 7 most_star -= 1 8 print(' *' * most_star) 9 break 10 star += 1 11 12 row = 1 13 most_row = 5 14 while row <= most_row: 15 print(' *' * row) 16 row += 1 17 row = most_row - 1 18 while row > 0: 19 print(' *' * row) 20 row -= 1 while循环只能打印一个方向,如果是两个相反的方向,需要两个while。两个while可以写成第二个while放在第一个while的末尾。

优秀的个人博客,低调大师

Java 学习(01)--DOS/环境/常量

1:计算机概述(了解) (1)计算机 (2)计算机硬件 (3)计算机软件 系统软件:window,linux,mac 应用软件:qq,yy,飞秋 (4)软件开发(理解) 软件:是由数据和指令组成的。(计算器) 开发:就是把软件做出来。 如何实现软件开发呢? 就是使用开发工具和计算机语言做出东西来 (5)语言 自然语言:人与人交流沟通的 计算机语言:人与计算机交流沟通的 C,C++,C#,Java (6)人机交换 图形界面:操作方便只管 DOS命令:需要记忆一些常见的命令 2:键盘功能键的认识和快捷键(掌握) (1)功能键的认识 tab shift ctrl alt windos 空格 上下左右 回车 截图 (2)快捷键 全选 Ctrl+A 复制 Ctrl+C 粘贴 Ctrl+V 剪切 Ctrl+X 撤销 Ctrl+Z 保存 Ctrl+S 3:常见的DOS命令(掌握) (1)常见的如下 盘符的切换 d:回车 目录的进入 cd javase cd javase\day01\code 目录的回退 cd.. cd\ 清屏 cls 退出 exit (2)其他的几个(了解) 创建目录 删除目录 创建文件 删除文件 显示目录下的内容 删除带内容的目录4:Java语言概述(了解) (1)Java语言的特点 有很多小特点,重点有两个开源,跨平台 (2)Java语言是跨平台的,请问是如何保证的呢?(理解) 针对不同的操作系统,提高不同的jvm来实现的。 (4)Java语言的平台 JavaSE JavaME--Android JavaEE 5:JDK,JRE,JVM的作用及关系(掌握) (1)作用 JVM:保证Java语言跨平台它是运行所有 Java 程序的抽象计算机 , 是 Java 语言的运行环境,它是 Java 最具吸 引力的特性之一, JVM 读取并处理编译过的与平台无关的字节码 (class) 文件。 Java 编译器针对 JVM 产生 class 文件,因此是独立于平台的。 Java 解释器负责将 JVM 的代码在特定的平台上运行。 Java 虚拟机是不跨平台的 JRE:Java程序的运行环境包括 Java 虚拟机 (JVM Java Virtual Machine) 和 Java 程序所需的核心类库等, 如果想要运行一个开发好的 Java 程序, 计算机中只需要安装 JRE 即可。 JDK:Java程序的开发环境 (jre、编译器)。 JDK 是提供给 Java 开发人员使 用的, 其中包含了 java 的开发工具,也包括了 JRE。 (2)关系 JDK:JRE+工具 JRE:JVM+类库 6:JDK的下载,安装,卸载(掌握) (1)下载到官网。 (2)安装 必须一步一步的安装,一般只要会点击下一步即可 注意:建议所有跟开发相关的软件都不要安装在有中文或者空格的目录下。 (3)卸载 a:控制面板 -- 添加删除程序 b:通过专业的软件卸载工具。(比如360的软件管家卸载) 7:第一个程序:HelloWorld案例(掌握) class HelloWorld { public static void main(String[] args) { System.out.println("HelloWorld"); } }(1)程序解释: A:Java程序的最基本单位是类,所以我们要定义一个类。 格式:class 类名 举例:class HelloWorld B:在类中写内容的时候,用大括号括起来。 C:Java程序要想执行,必须有main方法。 格式:public static void main(String[] args) D:要指向那些东西呢,也用大括号括起来。 E:你要做什么呢?今天我们仅仅做了一个简单的输出 格式:System.out.println("HelloWorld"); 注意:""里面的内容是可以改动的。 (2)Java程序的开发执行流程: A:编写java源程序(.java) B:通过javac命令编译生成.class文件 C:通过java命令运行.class文件 (要与 代码 中的类名相同) 8:常见的问题(掌握) (1)扩展名被隐藏 如何找到:查看--文件扩展名打上勾勾 (2)要求文件名称和类名一致。 实际上不这样做也是可以的。 但是,注意: javac后面跟的是文件名+扩展名 java后面跟的类名不带扩展名 (3)Java语言严格区分大小写,请注意。 (4)括号的配对问题。一般来说,括号都是成对出现的。 (6)遇到在类 HelloWorld 中找不到主方法,肯定是主方法的格式问题。 9:path环境变量(掌握) (1)path环境变量的作用 保证javac命令可以在任意目录下运行。 (2)path配置: 找到环境变量的位置,(我的电脑右击选属性--高级设置--环境变量)在系统变量里面 新建: 变量名:JAVA_HOME 变量值:D:\java\jdk8 修改: 变量名:Path 变量值:%JAVA_HOME%\bin 10:classpath环境变量(理解) (1)classpath环境变量的作用:保证class文件可以在任意目录下运行 (2)classpath环境变量的配置:找到环境变量的位置,在系统变量里面新建:变量名:classpath 变量值:d:\java教程\fy18\20180526\code\HelloWorld案例 (一般不用设置,文件较多时极难管理) 11:关键字(掌握) (1)被Java语言赋予特定含义的单词 (2)特点:全部小写。(3)注意事项:A:goto和const作为保留字存在。 B:类似于Notepad++这样的高级记事本会对关键字有特殊颜色标记 12:标识符(掌握) (1)就是给类,接口,方法,变量等起名字的字符序列 (2)组成规则: A:英文大小写字母 B:数字 C:$和_ (3)注意事项: A:不能以数字开头 B:不能是java中的关键字 C:区分大小写 13:注释(掌握) (1)就是对程序进行解释说明的文字 (2)分类: A:单行注释 // B:多行注释 /**/ C:文档注释(后面讲) /** */ (3)注释的作用 A:解释说明程序,提高了代码的阅读性。 B:可以帮助我们调试程序。 14:常量(掌握) (1)在程序执行的过程中,其值不发生改变的量(2)分类: A:字面值常量 B:自定义常量(后面讲)(3)字面值常量 A:字符串常量 "hello" B:整数常量 12,23 C:小数常量 12.345 D:字符常量 'a','A','0' E:布尔常量 true,false F:空常量 null (4) 在 Java 中针对整数常量提供了四种表现形式 A:二进制 由 0,1 组成。以 0b 开头。 B:八进制 由 0,1,...7 组成。以 0 开头。 C:十进制 由 0,1,...9 组成。整数默认是十进制。 D:十六进制 由 0,1,...9,a,b,c,d,e,f( 大小写均可 ) 组成。以 0x 开头。

优秀的个人博客,低调大师

day06_JDBC学习笔记

============================================================ 一、JDBC概述 为什么要使用JDBC? JDBC:JavaDataBaseConnectivity,是SUN公司提供的一套操作数据库的标准规范(技术)。 JDBC与数据库驱动的关系:接口与实现的关系。 JDBC规范(掌握四个核心对象): DriverManager类:用于注册驱动(创建连接对象)。java.sql.DriverManager; Connection接口:表示与数据库创建的连接 。java.sql.Connection; Statement接口:操作数据库sql语句的对象,并返回相应结果的对象。java.sql.Statement; preparedStatement接口:预编译对象,是Statement对象的子类。用于解决sql的注入问题。实际用的是这个类。java.sql.PreparedStatement; ResultSet接口:结果集或一张虚拟表(客户端存表数据的对象)。java.sql.ResultSet; 开发一个JDBC程序的准备工作: >JDBC规范在哪里: JDK中: java.sql.*; // jdk自身带的包 javax.sql.*; // 扩展包(企业级开发) >数据库厂商提供的驱动:jar文件(也即具体的实现) *.jar ============================================================ 二、开发一个JDBC程序(重要) 使用JDBC技术,通过java代码实现查询数据库中的数据并显示在java的控制台中。 1、先创建数据库表,并向表中添加测试数据。 create database day06; use day06; create table users ( id int primary key auto_increment, name varchar(40), password varchar(40), email varchar(60), birthday date ) character set utf8 collate utf8_general_ci; insert into users(name, password, email, birthday) values('zs', '123456', 'zs@sina.com', '1980-12-04'); insert into users(name, password, email, birthday) values('lisi', '123456', 'lisi@sina.com', '1981-12-04'); insert into users(name, password, email, birthday) values('wangwu', '123456', 'wangwu@sina.com', '1979-12-04'); 2、创建Java Project项目,添加数据库驱动(xxx.jar)。 3、实现JDBC操作。 ============================================================ 三、JDBC常用的类和接口详解 1、java.sql.Drivermanager类:注册驱动、建立连接 a、注册驱动 DriverManager.deregisterDriver(newcom.mysql.jdbc.Driver());// 不建议使用 原因有2个: >导致驱动被注册2次。 >强烈依赖数据库的驱动jar包 (若把奶瓶的BuildPath给Remove掉,代码就会报错,就能看到效果) 解决办法: Class.forName("com.mysql.jdbc.Driver");// 把奶瓶的BuildPath给Remove掉,代码也不会报错了 用到反射机制的知识:靠类的全路径来加载,解耦合了,不依赖数据库的驱动jar包了,以后会把上面的字符串放在配置文件里,更灵活了,便于后期维护。 b、与数据库建立连接 DriverManager类的静态方法: public staticConnectiongetConnection(Stringurl,Stringuser,Stringpassword) 试图建立到给定数据库URL的连接 DriverManager.getConnection("jdbc:mysql://localhost:3306/day06","root","root"); URL:是SUN公司与数据库厂商之间的一种协议。 jdbc:mysql://localhost:3306/day06 协议子协议 IP 数据库端口号数据库名称 mysql:jdbc:mysql://localhost:3306/day14或者 jdbc:mysql:///day14(默认连接本机的数据库) oracle:jdbc:oracle:thin:@localhost:1521:sid 瘦客户端,比如:玩页游协议 子协议子子协议 IP 数据库端口号数据库名称 oracle:jdbc:oracle:thick:@localhost:1521:sid 胖客户端,比如:LOL、魔兽世界(需要下载软件) 与数据库建立连接的方式 第一种: //publicstaticConnectiongetConnection(Stringurl,Stringuser,Stringpassword) Connectionconn=DriverManager.getConnection("jdbc:mysql://localhost:3306/day06","root","root"); 第二种: //publicstaticConnectiongetConnection(Stringurl,Propertiesinfo) Propertiesinfo=newProperties();//要参考数据库文档 info.setProperty("user","root"); info.setProperty("password","root"); Connectionconn=DriverManager.getConnection("jdbc:mysql://localhost:3306/day06",info); 第三种: //publicstaticConnectiongetConnection(Stringurl) Connectionconn=DriverManager.getConnection("jdbc:mysql://localhost:3306/day06?user=root&password=root"); //模拟表单form提交的两种方式:GET和POST 实际开发常用第一种。 扩展内容:演示3个案例的话需要写3个main方法,所以有了快速测试的方法 ==> junit技术 packagecom.itheima.junitdemo; publicclassCalc{ publicintadd(inta,intb){ returna+b; } publicdoublediv(doublea,intb){ returna/b; } } ------------------------------------------- packagecom.itheima.junitdemo; importorg.junit.Assert; importorg.junit.Test; //注:测试的方法有要求:不能有返回值,不能有参数。 publicclassTestCalc{ @Test publicvoidtest1(){ Calcc=newCalc(); Assert.assertEquals(8,c.add(3,5));//assert断言 } @Test publicvoidtest2(){ Calcc=newCalc(); Assert.assertEquals(3,c.div(10,3),0.4); } } ----------------------------------------------------------------------------- 2、java.sql.Connection接口:一个连接(与数据库连接的一座桥梁) 该接口的实现在数据库驱动jar包中。所有与数据库交互都是基于连接对象的。 //创建执行sql语句的对象Satement(接口) //Connection(接口)的方法:StatementcreateStatement() Statementstmt=conn.createStatement(); ----------------------------------------------------------------------------- 3、java.sql.Statement接口:操作sql语句,并返回相应结果的对象(小货车) 该接口的实现在数据库驱动jar包中。用于执行静态 SQL 语句并返回它所生成结果的对象。 //执行sql语句,该语句返回单个ResultSet结果集对象。 //Statement(接口)的方法:ResultSetexecuteQuery(Stringsql) //注意;该方法只能执行select语句。 ResultSetrs=stmt.executeQuery("select*fromusers"); //Statement(接口)的方法:int executeUpdate(Stringsql) //根据执行的DML(insertupdatedelete)语句,返回受影响的行数。 // 服务器端叫法:insert、delete、update、select(增删改查) // 客户端的叫法:create、read、update、delete(CRUD)(增删改查) inti=stmt.executeUpdate("INSERTINTOusersVALUES(4,'tom','123','tom@163.com','2015-09-28')"); inti=stmt.executeUpdate("UPDATEusersSETNAME='jerry',PASSWORD='333',email='jerry@163.com'WHEREid=4"); inti=stmt.executeUpdate("DELETEFROMusersWHEREid=4"); //Statement(接口)的方法:booleanexecute(Stringsql) // 这个方法很奇葩!!! //此方法可以执行任意sql语句。返回boolean值,表示是否返回ResultSet结果集。 //仅当执行select语句,且有返回结果时返回true,其它语句都返回false。 ----------------------------------------------------------------------------- 4、java.sql.ResultSet接口:结果集(客户端存表数据的对象) a、封装结果集 提供一个游标,默认游标指向结果集第一行之前(即表头)。 调用一次booleannext(),游标向下移动一行。 提供一些getXxx()方法。 ------------------------------------------- 将结果集中的数据封装到javaBean类中,javaBean就是一普通java类,该类中只有private类型的成员变量、无参构造方法和getter/setter方法。 java的数据类型与数据库中的类型的关系: JAVA DB byte tityint 1字节 short smallint 2字节 intint 4字节 long bigint 8字节 float float doubledouble String char 或者 varchar Datedate ------------------------------------------- ResultSet结果集封装数据的方法: ObjectgetObject(intcolumnIndex) 根据序号取值,索引从1开始 ObjectgetObject(StringColomnName) 根据列名取值 booleannext() 将光标从当前位置向下移动一行 intgetInt(intcolIndex) 以int 形式获取ResultSet结果集当前行指定列号值 intgetInt(StringcolLabel) 以int 形式获取ResultSet结果集当前行指定列名值 floatgetFloat(intcolIndex) 以float 形式获取ResultSet结果集当前行指定列号值 floatgetFloat(StringcolLabel) 以float形式获取ResultSet结果集当前行指定列名值 StringgetString(intcolIndex) 以String形式获取ResultSet结果集当前行指定列号值 StringgetString(StringcolLabel) 以String 形式获取ResultSet结果集当前行指定列名值 DategetDate(intcolumnIndex) 以Date形式获取ResultSet结果集当前行指定列号值 DategetDate(StringcolumnName) 以Date形式获取ResultSet结果集当前行指定列名 voidclose() 关闭ResultSet对象 ------------------------------------------- 1 package com.itheima.entitydemo; 2 3 import java.util.Date; 4 5 /* 6 * 一般实体类的类名和数据库的表名一致。(注意:若数据库的表名单词带s的,则实体类名就去掉s) 7 * 实体类的成员变量名和数据库表中的列名一致。(这是一个约定,网站开发的时候会提到) 8 */ 9 public class User { 10 private int id; 11 private String name; 12 private String password; 13 private String email; 14 private Date birthday; 15 16 public int getId() { 17 return id; 18 } 19 20 public void setId(int id) { 21 this.id = id; 22 } 23 24 public String getName() { 25 return name; 26 } 27 28 public void setName(String name) { 29 this.name = name; 30 } 31 32 public String getPassword() { 33 return password; 34 } 35 36 public void setPassword(String password) { 37 this.password = password; 38 } 39 40 public String getEmail() { 41 return email; 42 } 43 44 public void setEmail(String email) { 45 this.email = email; 46 } 47 48 public Date getBirthday() { 49 return birthday; 50 } 51 52 public void setBirthday(Date birthday) { 53 this.birthday = birthday; 54 } 55 56 @Override 57 public String toString() { 58 return "User [id=" + id + ", name=" + name + ", password=" + password + ", email=" + email + ", birthday=" 59 + birthday + "]"; 60 } 61 62 } User.java 1 package com.itheima.entitydemo; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.ResultSet; 6 import java.sql.Statement; 7 import java.util.ArrayList; 8 import java.util.List; 9 10 import org.junit.Test; 11 12 /* 13 * 服务器端叫法:insert、delete、update、select (增删改查) 14 * 客户端的叫法:create、read、update、delete (CRUD)(增删改查) 15 */ 16 public class TestCRUD { 17 18 @Test 19 public void testSelect() throws Exception { 20 // 加载驱动 21 Class.forName("com.mysql.jdbc.Driver"); 22 23 // 获取连接对象Connection(注意:能用接口的就不用实现类,多态=>对象上传=>向上转型=>里氏替换,利于后期代码扩展) 24 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day06", "root", "root"); 25 26 // 获取执行sql语句的对象Statement 27 Statement stmt = conn.createStatement(); 28 29 // 执行sql的查询语句,并返回结果 30 ResultSet rs = stmt.executeQuery("select * from users"); 31 32 // 把取到的数据装到集合中 33 List<User> list = new ArrayList<User>(); 34 35 // 处理结果 36 User u = null; 37 while (rs.next()) { 38 u = new User(); 39 u.setId(rs.getInt("id")); 40 u.setName(rs.getString("name")); 41 u.setPassword(rs.getString("password")); 42 u.setEmail(rs.getString("email")); 43 u.setBirthday(rs.getDate("birthday")); 44 list.add(u); // 把对象添加到集合中去 45 } 46 47 // 遍历集合(增强for) 48 for (User user : list) { 49 System.out.println(user); 50 } 51 52 // 关闭资源 53 rs.close(); 54 stmt.close(); 55 conn.close(); 56 } 57 58 @Test 59 public void testInsert() throws Exception { 60 // 加载驱动 61 Class.forName("com.mysql.jdbc.Driver"); 62 63 // 获取连接对象Connection(注意;能用接口的就不用实现类,多态=>对象上传=>向上转型=>里氏替换,利于后期代码扩展) 64 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day06", "root", "root"); 65 66 // 获取执行sql语句的对象Statement 67 Statement stmt = conn.createStatement(); 68 69 // 执行sql的插入语句,并返回结果 70 int i = stmt.executeUpdate("INSERT INTO users VALUES (4, 'tom', '123','tom@163.com', '2015-09-28')"); 71 72 // 处理返回的结果 73 if (i > 0) { 74 System.out.println("success"); 75 } 76 77 // 关闭资源 78 stmt.close(); 79 conn.close(); 80 } 81 82 @Test 83 public void testUpdate() throws Exception { 84 // 加载驱动 85 Class.forName("com.mysql.jdbc.Driver"); 86 87 // 获取连接对象Connection(注意;能用接口的就不用实现类,多态=>对象上传=>向上转型=>里氏替换,利于后期代码扩展) 88 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day06", "root", "root"); 89 90 // 获取执行sql语句的对象Statement 91 Statement stmt = conn.createStatement(); 92 93 // 执行sql的更新语句,并返回结果 94 int i = stmt.executeUpdate("UPDATE users SET NAME = 'jerry', PASSWORD = '333', email = 'jerry@163.com' WHERE id = 4"); 95 96 // 处理返回的结果 97 if (i > 0) { 98 System.out.println("success"); 99 } 100 101 // 关闭资源 102 stmt.close(); 103 conn.close(); 104 } 105 106 @Test 107 public void testDelete() throws Exception { 108 // 加载驱动 109 Class.forName("com.mysql.jdbc.Driver"); 110 111 // 获取连接对象Connection(注意;能用接口的就不用实现类,多态=>对象上传=>向上转型=>里氏替换,利于后期代码扩展) 112 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day06", "root", "root"); 113 114 // 获取执行sql语句的对象Statement 115 Statement stmt = conn.createStatement(); 116 117 // 执行sql的删除语句,并返回结果 118 int i = stmt.executeUpdate("DELETE FROM users WHERE id = 4"); 119 120 // 处理返回的结果 121 if (i > 0) { 122 System.out.println("success"); 123 } 124 125 // 关闭资源 126 stmt.close(); 127 conn.close(); 128 } 129 130 } TestCRUD.java b、可移动游标的方法(现在很少用了,只有next()还常用) ResultSet结果集的方法: booleannext() 将光标从当前位置向前移一行 booleanprevious() 将光标移动到此ResultSet对象的上一行 booleanabsolute(introw) 参数是当前行的索引,从1开始,根据行的索引定位移动的指定索引行 voidafterLast() 将光标移动到末尾,正好位于最后一行之后 voidbeforeFirst() 将光标移动到开头,正好位于第一行之前(即表头) ----------------------------------------------------------------------------- 5、释放资源 资源有限,要正确关闭。 原则:在使用对象之前,先判断对象是否为空。 把某一部分代码加上try...catch...的快捷键:Alt+Shift+Z 1 package com.itheima.jdbcdemo; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import java.sql.Statement; 8 9 /* 10 * 使用JDBC技术,通过java代码实现查询数据库中的数据并显示在java的控制台中。 11 * 12 * 演示正确释放资源。 13 * 14 * 把某一部分代码加上try...catch...的快捷键:Alt + Shift + Z 15 */ 16 public class Demo4 { 17 18 public static void main(String[] args) { 19 // 获取连接对象Connection 20 Connection conn = null; 21 // 获取执行sql语句的对象Statement 22 Statement stmt = null; 23 // 执行sql查询语句,并返回结果 24 ResultSet rs = null; 25 try { 26 // 加载驱动 27 Class.forName("com.mysql.jdbc.Driver"); 28 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day06", "root", "root"); 29 stmt = conn.createStatement(); 30 rs = stmt.executeQuery("select * from users"); 31 // 处理返回的结果 32 while (rs.next()) { 33 // 根据列名取值,顺序自己定,更灵活 34 System.out.println(rs.getObject("id")); 35 System.out.println(rs.getObject("name")); 36 System.out.println(rs.getObject("password")); 37 System.out.println(rs.getObject("email")); 38 System.out.println(rs.getObject("birthday")); 39 } 40 } catch (Exception e) { 41 e.printStackTrace(); 42 } finally { 43 // 关闭资源 44 if (rs != null) { 45 try { 46 rs.close(); 47 } catch (SQLException e) { 48 e.printStackTrace(); 49 } 50 } 51 if (stmt != null) { 52 try { 53 stmt.close(); 54 } catch (SQLException e) { 55 e.printStackTrace(); 56 } 57 } 58 if (conn != null) { 59 try { 60 conn.close(); 61 } catch (SQLException e) { 62 e.printStackTrace(); 63 } 64 } 65 } 66 } 67 } 演示正确释放资源 ============================================================ 四、使用JDBC实现CRUD操作 注意: *一般实体类的类名和数据库的表名一致。(注意:若数据库的表名单词带s的,则实体类名就去掉s) *实体类的成员变量名和数据库表中的列名一致。(这是一个约定,网站开发的时候会提到) 后续演示代码的实体类的类名为User。 其实名字可以随意起的,但是一般要求我们做到见名知意。 ============================================================ 五、实现一个用户登录的功能 ============================================================ 六、解决SQL注入问题:preparedStatement(预编译语句) preparedStatement(接口):预编译对象,是Statement(接口)对象的子类。 特点:(安全高效,防止恶义SQL语法) 1、性能要高;PreparedStatement实例包含已编译的SQL语句,所以其执行速度要快于Statement对象。 2、会把sql语句先编译。 3、sql语句中的参数会发生变化,过滤掉用户输入的关键字。 package com.itheima.service; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import com.itheima.entity.User; import com.itheima.util.DBUtils; public class DoLogin { /** * 根据姓名和密码查询用户信息 * @param name * @param password * @return User */ public User findUser(String name, String password) { Connection conn = null; // Statement stmt = null; PreparedStatement stmt = null; ResultSet rs = null; User u = null; try { conn = DBUtils.getConnection(); // stmt = conn.createStatement(); // String sql = "select * from users where name = '" + name + "' and password = '" + password + "'"; // rs = stmt.executeQuery(sql); String sql = "select * from users where name = ? and password = ?"; stmt = conn.prepareStatement(sql); stmt.setString(1, name); // 给?赋值 stmt.setString(2, password); // 给?赋值 rs = stmt.executeQuery(); if (rs.next()) { u = new User(); u.setId(rs.getInt("id")); u.setName(rs.getString("name")); u.setPassword(rs.getString("password")); u.setEmail(rs.getString("email")); u.setBirthday(rs.getDate("birthday")); } } catch (Exception e) { e.printStackTrace(); } finally { DBUtils.closeAll(rs, stmt, conn); } return u; } } ============================================================我的GitHub地址: https://github.com/heizemingjun 我的博客园地址: http://www.cnblogs.com/chenmingjun 我的蚂蚁笔记博客地址: http://blog.leanote.com/chenmingjun Copyright ©2018 黑泽明军 【转载文章务必保留出处和署名,谢谢!】

优秀的个人博客,低调大师

Java学习笔记--泛型(巨细)

泛型: 泛型在java基础中属于重要的一部分,掌握泛型是必要的。接下来以我的理解来解释一下 背景:编译器是先通过检查代码中泛型的类型 再进行类型擦除 再进行编译的 什么是泛型, 什么时候需要泛型, 泛型怎么用, 泛型注意的问题。 目前我接触的泛型应用就是集合使用泛型达到 一个集合里面只有一种类型的数据 泛型的好处: 1. 将运行时的异常提前至了编译时。 2. 避免了无谓的强制类型转换 。 泛型在集合中的常见应用: ArrayList<String> list = new ArrayList<String>(); true 推荐使用。 ArrayList<Object> list = new ArrayList<String>(); false ArrayList<String> list = new ArrayList<Object>(); false //以下两种写法主要是为了兼顾新老系统的兼用性问题。 * ArrayList<String> list = new ArrayList(); true ArrayList list = new ArrayList<String>(); true 注意: 泛型没有多态的概念,左右两边的数据 类型必须 要一致,或者只是写一边的泛型类型。 推荐使用: 两边都写泛型。 具体集合是上面类型的 是看左边的泛型是什么 举个常见的例子: 集合: ArrayList list = new ArrayList(); list.add("11"); list.add(3); 这个时候ArrayList集合中存储了多种类型,是不是看起来很不顺眼,日常应用中 我们想要的结果是 一个集合里面存储的类型是同一个。 如: ArrayList<String> list = new ArrayList<String>(); list.add("11"); list.add(3); //这个时候 集合list只能存放String类型的数据 //如果存储了其他的如 Integer类型之类的就会报错,是在编译前检查 泛型方法 public <T> T showKeyName(T a){//<T>是声明泛型方法 return a; } 泛型类: 自定义泛型: 自定义泛型就是一个数据类型的占位符或者是一个数据类型的变量。 class Point< T>{ // 此处可以随便写标识符号,T是type的简称 一般都是T private T var ; // var的类型由T指定,即:由外部指定 public T getVar(){ // 返回值的类型由外部决定 return var ; } public void setVar(T var){ // 设置的类型也由外部决定 this.var = var ; } }; 注意:在方法上自定义泛型,这个自定义泛型的具体数据类型 是在调用该方法的时候传入实参时确定具体的数据类型的。 泛型类还可以同时定义多个泛型 栗子: class Point< K,V>{ // 不一样的泛型 private K var ; // var的类型由K指定 private V time ; //time的类型由V指定 } }; 泛型类中要注意一: 静态方法无法访问类上定义的泛型 如果静态方法要使用泛型的话,必须将静态方法也定义成泛型方法 (原因我也不知道) 声明泛型一定要写在static后,返回值类型之前 class MyMessage<T>{ public T qu(T a) { System.out.println("qu"); return a; } public static <t> t ha(t a){ //静态函数需要重新泛型 System.out.println("ha"); return a; } } class new1{ public static void main(String[] args) { System.out.println(MyMessage.ha("aaa")); } } 注意 如果是调用静态的泛型函数时不能MyMessage<String>.ha("aaa") 传入具体泛型 泛型类中要注意二: 泛型类与泛型方法共存: public class Test1<T>{ public void testMethod(T t){ System.out.println(t.getClass().getName()); } public <T> T testMethod1(T t){ return t; } } 上面代码中,Test1<T> 是泛型类,testMethod 是泛型类中的普通方法, 而testMethod1是一个泛型方法。而泛型类中的类型参数与泛型方法中的类型参数 是没有相应的联系的,泛型方法始终以自己定义的类型参数为准。 意思就是调用testMethod1 结果是里面里面的那个决定的 而不是外面的那个类 如果在一个泛型类中存在泛型方法,那么两者的类型参数最好不要同名。 泛型方法与可变参数 再看一个泛型方法和可变参数的例子: public <T> void printMsg( T... args){ for(T t : args){ System.out.println(t); } } 泛型父类子类继承: class Son1 extends MyMessage<String>{ //指的是父类里面T是用String来代替了 //如果有重写的话 那么重写的父类类型是String public String ha(String a) { return a; } } class Son2<T> extends MyMessage<T>{ public T xx(T a) { return a; } } 泛型接口: class person<T>{ public T a(T az) { System.out.println("futher"); return az; } } class son extends person<Integer>{ @Override public Integer a(Integer az) { System.out.println("son"); return az; } } 注意:不能对确切的泛型类型使用instanceof操作。如下面的操作是非法的,编译时会出错。 List<String> aList=new ArrayList<String>(); aList instanceof List<String>//编译错误 泛型有个叫泛型擦除的 意思就是说 虽然有不同的泛型 但是在编译后计算机只看到Object类型的 举个栗子: List<String> aList1=new ArrayList<String>(); List<Integer> aList2=new ArrayList<Integer>(); 编译后就变成 List aList1=new ArrayList(); List aList2=new ArrayList(); //在编译生成的字节码中不包含泛型中的类型参数,类型参数会在编译时去掉。 //例如:List<String> 和 List<Integer> 在编译后都变成 List。 泛型通配符 先来看一个问题: public void showKeyValue1(Generic<Number> obj){ Log.d("泛型测试","key value is " + obj.getKey()); } Generic<Integer> gInteger = new Generic<Integer>(); Generic<Number> gNumber = new Generic<Number>(); showKeyValue(gInteger); // showKeyValue这个方法编译器会为我们报错: 我们来解决一下为什么会报错 问: 首先有个疑惑 不是有泛型擦除吗?为什么Generic<Integer>传递给 Generic<Number>的参数会报错 编译后不是变成Generic类型传递给Generic吗? 答:类型检查是在编译前判断的 所以是先判断类型 然后再泛型擦除 先来看一个问题: public void showKeyValue1(Generic<Number> obj){ Log.d("泛型测试","key value is " + obj.getKey()); } Generic<Integer> gInteger = new Generic<Integer>(); Generic<Number> gNumber = new Generic<Number>(); showKeyValue(gInteger); // showKeyValue这个方法编译器会为我们报错: 我们来解决一下为什么会报错 问: 首先有个疑惑 不是有泛型擦除吗?为什么Generic<Integer>传递给 Generic<Number>的参数会报错 编译后不是变成Generic类型传递给Generic吗? 答:类型检查是在编译前判断的 所以是先判断类型 然后再泛型擦除 问:Integer不是继承Number吗 为什么还无法传递? 答:相同参数类型的泛型类的继承关系取决于泛型类自身的继承结构。 List<Integer>和List<Number>是不同的对象 没有继承关系 前提泛型类自身一定要有继承关系 而泛型继承没有一点卵用 泛型一定要相同才行 (如果有通配符那么两个维度的继承同时满足也可以) 例如 List<String> 是 Collection<String> 的子类 List<Integer> 不是 Collection<Number> 的子类 栗子: 传入的参数是List<Integer> 形参1.public static String print(List<Integer> a) 可以通过 形参2.public static String print(List<Number> a) 不能通过 两个维度没有继承关系 形参3.public static<T> String print(List<T> a) 可以通过 形参4.public static String print(List<?> a) 可以通过 public static void zz(Collection<Integer> a) 可以通过 因为存在继承 public static void zz(Collection<Number> a) 不可以 传入参数List<String> 形参1 public static void xx(List<?> a)可以 形参2 public static void xx(List<? extends Number> a) 不可以 因为限制了范围 当类型声明中使用通配符 ? 时, 其子类型可以在两个维度上扩展。 例如 Collection<Number> 在维度1上扩展:List<? extends Number> 在维度2上扩展:Collection<Integer> 两个维度上同时扩展:List<Integer> 意思就是 Collection<Number>可以接收List<Integer> 总结: 引入泛型之后的类型系统增加了两个维度:一个是类型参数自身的继承体系结构, 另外一个是泛型类或接口自身的继承体系结构。第一个指的是对于 List<String> 和List<Object>这样的情况,类型参数String是继承自Object的。 而第二种指的是 List接口继承自Collection接口。 对于这个类型系统,有如下的一些规则: 相同类型参数的泛型类的关系取决于泛型类自身的继承体系结构。 即List<String>是Collection<String> 的子类型, List<String>可以替换Collection<String>。 这种情况也适用于带有上下界的类型声明。 当泛型类的类型声明中使用了通配符的时候,其子类型可以在两个维度上分别展开 如对Collection<? extends Number>来说, 其子类型可以在Collection这个维度上展开, 即List<? extends Number>和Set<? extends Number>等; 也可以在Number这个层次上展开,即Collection<Double>和 Collection<Integer>等。如此循环下去,ArrayList<Long>和 如果泛型类中包含多个类型参数,则对于每个类型参数分别应用上面的规则。 通配符写法: public static void zz(List<?> a) 通配符是实参而且还是根实参 不是形参 所以可接受任何泛型对象 还可以定义上边界和下边界: 上边界: public static void zz(List<? extends Number> a){ // 只能接收Number及其Number的子类 } 下边界: public static void zz(List<? super Integer > a){ // 只能接收Integer及其Integer的父类 } 如果类型的变量有限定那么原始类型就用第一个边界的类型变量代替 上界通配符后不能往集合添加元素 取出的元素也是上界父元素 add受限制 下届通配符 可以添加元素 必须是子类或者本身 取出的元素类型都是Object get受限制 获取数据用extend通配符 添加数据用super通配符 两个都想就不别用通配符 只有super有权限添加 其他的只能查看 提一下: Java泛型无法向上转型 class Info< T>{ private T var ; // 定义泛型变量 public void setVar(T var){ this.var = var ; } public T getVar(){ return this.var ; } public String toString(){ // 直接打印 return this.var.toString() ; } }; public class GenericsDemo23{ public static void main(String args[]){ Info< String> i1 = new Info< String>() ; // 泛型类型为String Info< Object> i2 = null ; i2 = i1 ; //这句会出错 incompatible types 因为两者不是一个对象 } }; 还有: 泛型的类型参数不能用在Java异常处理的catch语句中。因为异常处理是由JVM在运行时刻来进行的。由于类型信息被擦除,JVM是无法区分两个异常类型MyException;和MyException的。对于JVM来说,它们都是 MyException类型的。也就无法执行与异常对应的catch语句。 重点:在泛型中不能使用基本数据类型,如果需要使用基本数据类型,那么就使用基本数据类型对应的包装类型。 桥方法: 看看下面这个类SonPair class SonPair extends Pair<String>{ public void setFirst(String fir){....} } 很明显,程序员的本意是想在SonPair类中覆盖父类Pair的setFirst(T fir)这个方法。但事实上,SonPair中的setFirst(String fir)方法根本没有覆盖住Pair中的这个方法。 原因很简单,Pair在编译阶段已经被类型擦除为Pair了,它的setFirst方法变成了setFirst(Object fir)。 那么SonPair中setFirst(String)当然无法覆盖住父类的setFirst(Object)了。 这对于多态来说确实是个不小的麻烦,我们看看编译器是如何解决这个问题的。 编译器 会自动在 SonPair中生成一个桥方法(bridge method ) : public void setFirst(Object fir) { setFirst((String) fir) } 这样,SonPair的桥方法确实能够覆盖泛型父类的setFirst(Object) 了。而且桥方法内部其实调用的是子类字节setFirst(String)方法。对于多态来说就没问题了。 1.2)问题还没有完,多态中的方法覆盖是可以了,但是桥方法却带来了一个疑问: 现在,假设 我们还想在 SonPair 中覆盖getFirst()方法呢? class SonPair extends Pair<String> { public String getFirst(){....} } 由于需要桥方法来覆盖父类中的getFirst,编译器会自动在SonPair中生成一个 public Object getFirst()桥方法。 (干货——引入了桥方法,该方法是编译器生成的,不是程序员码出来的) 但是,疑问来了,SonPair中出现了两个方法签名一样的方法(只是返回类型不同): ①String getFirst() // 自己定义的方法 ②Object getFirst() // 编译器生成的桥方法 难道,编译器允许出现方法签名相同的多个方法存在于一个类中吗?事实上有一个知识点可能大家都不知道: ① 方法签名 确实只有方法名+参数列表 。这毫无疑问! ② 我们绝对不能编写出方法签名一样的多个方法 。如果这样写程序,编译器是不会放过的。这也毫无疑问! ③ 最重要的一点是: JVM会用参数类型和返回类型来确定一个方法。 一旦编译器通某种方式自己编译出方法签名一样的两个方法 (只能编译器自己来创造这种奇迹,我们程序员却不能人为的编写这种代码)。JVM还是能够分清楚这些方法的,前提是需要返回类型不一样。 结论: 在编译阶段,所有泛型类的类型参数都会被Object或者它们的限定边界来替换。(类型擦除) 在继承泛型类型的时候,桥方法的合成是为了避免类型变量擦除所带来的多态灾难。 最后提一下泛型数组 : List<String>[] ls = new ArrayList<String>[10]; 而使用通配符创建泛型数组是可以的,如下面这个例子: List<?>[] ls = new ArrayList<?>[10]; 泛型数组在java中是不支持的 因为泛型擦除的原因 如果创建了泛型数组 Object[] aa=new ArrayList[]; 加入可以创建 aa[0]=new ArrayList(); 编译器被骗 那么就是不安全的 还有协变……不是很了解

优秀的个人博客,低调大师

Apache Phoenix学习记录(SQL on HBase)

1 使用概述 Phoenix是基于HBase的SQL中间件产品,由Salesforce.com公司开源并托管于Github上。对于熟悉关系型数据库的开发人员来说,通过Phoenix可以像使用MySQL等关系型数据库一样使用HBase中的数据表。值得注意的是,它还提供了JDBC驱动包供Java程序访问数据。在实现时,充分利用了HBase协处理器和过滤器等底层 2 环境配置 首先需要安装好HBase集群,且采用的版本在0.94.4以上,JDK版本1.6以上。本文采用的phoenix版本为phoenix-2.0.1(http://phoenix-bin.github.com/client/phoenix-2.0.1-install.tar),所以如果有相关差异或更改,请以官方公布文档为准。 安装phoenix非常简单,从下载的tar包中取出phoenix-2.0.1.jar,将其放入HBase集群中所有RS节点安装目录lib中,同时记得移除之前安装的phoenix老版本,如果安装过的话。然后重启所有RS节点服务。如果采用Java代码访问,请采用与之匹配的client版本,比如本文的phoenix-2.0.1-client.jar。 为便于测试,可将下载的包内容放置到HBase集群某个节点机器上,比如本文将其放置到HMaster机器vnode120的$HBASE_HOME phoenix中,为检验phoenix是否安装成功,请进入$HBASE_HOME/phoenix/bin目录,并赋予所有*.sh可执行权限,操作如下: image sqlline.sh为其提供的命令行工具,可以在其中执行建表,查询等相关动作。运行该脚本需要跟zk参数,vnode121为某个zk节点。连上后,执行!tables会列出所有通过phoenix建的表,其中SYSTEM.TABLE这张表默认会存在,其中存放phoenix实现中的数据类型映射等信息。当能执行这些操作后,说明phoenix功能已经正常整合进现有HBase集群中,您接下来就可以体验HBase之上执行SQL功能的奇妙之旅了。 3 SQL特性详解 1)create:可以创建一张表或视图。表名如果没有用双引号括起来,默认都会使用其对应的大写字母名字表示,括起来后跟括起来的值保持一致。如果创建的表已经存在,且其不是通过phoenix create语法创建的,则可以继续使用phoenix create创建同名表,不影响原有表数据,但会影响通过phoenix select结果值存在部分不需要的值。创建视图时,需要对应的表和列族已存在,不能对表中数据进行更新操作。建表语句中,还可以附加一些HBase表、列族配置选项,如VERSIONS、MAX_FILESIZE etc. CREATETABLE IF NOT EXISTS my_table ( id char(10) not null primary key, value integer); CREATETABLE IF NOT EXISTS my_schema.my_table ( id char(10) not null primary key,value integer) DATA_BLOCK_ENCODING='NONE',VERSIONS=10,MAX_FILESIZE=20480; 2)alter:可添加或删除一列或更新表属性。被移除的列,其上数据会被删除。如果该列是主键,不能被移除,如果移除列的是一个视图,数据是不会受影响的。 ALTERTABLE my_table ADD dept_name varchar(50) ALTERTABLE my_table DROP COLUMN parent_id ALTERTABLE my_table SET IMMUTABLE_ROWS=true 3)drop:删除表或视图。如果删除表,表中数据也会被删除,如果是视图则不受影响。 DROPTABLE my_schema.my_table DROP VIEW my_view 4)upsert:更新或插入数据。如果表中不存在该数据则插入,否则更新,所以可以看出phoenix没有单独定义insert 或update命令。列列表可以省略,但后面插入的值顺序需要与表schema定义顺序保持一致,也可自己定义插入哪些column对应值,顺序与之对应即可。目前还支持一种选择性upsert的方式,它将另外一个查询的结果作为值插入表中。如果auto commit开启的话,会在服务端就提交了,否则会缓存到客户端,等着显式提交的时候进行批量upsert,通过配置” phoenix.mutate.upsertBatchSize”指定大小,默认10000行/次。 UPSERTINTO TEST VALUES('foo','bar',3); UPSERTINTO TEST(NAME,ID) VALUES('foo',123) 5)delete:删除指定行。如果auto commit开启,则会直接在服务端执行删除。 DELETE FROM TEST; DELETE FROM TEST WHERE ID=123; 6)index:二级索引。在表或视图上创建二级索引,当前版本仅支持对具有IMMUTABLE_ROWS属性的表上添加二级索引。目前实现是在数据行插入后便插入了索引。当创建了索引后,其实也会在HBase中创建一张表,表名为该二级索引名,所以还可对该index指定创建表相关参数。同时还可删除索引和修改索引。 CREATEINDEX my_idx ON sales.opportunity(last_updated_date DESC) DROPINDEX my_idx ON sales.opportunity ALTERINDEX my_idx ON sales.opportunity DISABLE 7)explain:执行计划。提供一个很简单的方式查看执行给定命令所需的逻辑步骤。每个步骤局势以单行字符串进行输出表示。这个可以很容易定位查询的性能瓶颈,或者所建二级索引是否生效等。 explain select * from test where age>0; 8)其他 constraint定义主键约束,默认按照列升序排列: CONSTRAINTmy_pk PRIMARY KEY (host,created_date) 选项,如之前用到的IMMUTABLE_ROWS=true,默认设置了这个选项的表才允许建索引。Phoenix默认是修改HBase元数据来使之生效,适用于HColumnDescriptor和HTableDescriptor相关选项。值得一提的是SALT_BUCKETS选项,它为每个rowkey预置一个字节,使其分布在不同rs上来避免写热点rs。 IMMUTABLE_ROWS=true SALT_BUCKETS=10 hint,可重置默认的查询行为。一般用于sql调优。目前支持SKIP_SCAN,RANGE_SCAN,NO_INTRA_REGION_PARALLELIZATION,NO_INDEX,INDEX5个hint。 select /*+NO_INDEX / from test where age>0 建表,建索引或alter等操作的时候,名称都可以用.分隔,如果是表,则前部分为schema名(默认null),如果是column,则前部分是family名(默认’_0’)。不用双引号括起来的时候为大小写不敏感的。 选择表达式可以用*和<familyName>.*来表示所有列都选择出来,或指定列族下所有列都选择出来,注意的时候familyName是大小写敏感的,列名是大小写不敏感的。 为表定义分割点,可以使用preparedStatement.setBinary(int,byte[])提供任意字节的分割。 目前不支持join和子查询,可以为表和列定义别名,方法是使用as或直接将别名跟在真名后面。 目前查询支持排序,比如按照某列升序,降序等。ORDER BY NAME ASC NULLSLAST。 支持的关系连接符有AND和OR。如果使用LIKE,可以用通配符_(单个字符)和%(任意字符)。若查询的字符串本身就包括则需要对其转义()。Between是个闭区间[5,10] 比较运算符有<>,<=,>=,=,<,>,!=其中<>与!=等效。字符串连接可以用||,数字和日期类型可以做+,-,*,/。 4 内置函数 支持的聚合函数有: Ø AVG:求平均,如果没有返回NULL Ø SUM: Ø COUNT:求行数,如果指定某列,则返回该列非空个数,如果为*或1,则返回所有行,加上distinct则返回不相同的行数 Ø MAX:求最大值 Ø MIN:求最小值 Ø PERCENTILE_CONT:指定?? Ø PERCENTILE_DISC:指定占比的列具体值是多少 Ø PERCENT_RANK:指定值占的百分比,PERCENT_RANK( 39 ) WITHINGROUP (ORDER BY id ASC) Ø STDDEV_SAMP:样本标准差 Ø STDDEV_POP:总体标准差 支持的字符串函数: Ø SUBSTR:取子串,默认是基于1的,如果想基于0,则指定0,如果指定为负数,则是从字符串结尾算起 Ø TRIM:去除字符串头尾空格 Ø LTRIM:去除字符串左侧空格 Ø RTRIM:去除字符串右侧空格 Ø LENGTH:返回字符串长度 Ø REGEXP_SUBSTR:通过指定正则表达式获取子串 Ø REGEXP_REPLACE:正则替换 Ø UPPER:大写转换 Ø LOWER:小写转换 Ø REVERSE:字符串反转 Ø TO_CHAR:将日期、时间、时间戳或数字格式化为一个字符串。默认日期格式为yyyy-MM-dd HH:mm:ss,数字格式为#,##0.###。 支持的时间、日期函数: Ø ROUND:四舍五入? Ø TRUNC:截断 Ø TO_DATE:转换为date类型 Ø CURRENT_DATE:返回RS上当前日期 Ø CURRENT_TIME:返回RS上当前时间 支持的时间、日期函数: Ø TO_NUMBER:转换日期、时间、时间戳为一个数字,可接受格式化串? Ø COALESCE:指定默认值,如果相应值为null 5 数据类型 Ø INTEGER:范围为-2147483648 到 2147483647,与java.lang.Integer映射。但注意的是其二进制表示需要其会把第一个符号位进行翻转,这样保证负数排列在正数前面。 Ø UNSIGNED_INT:范围为0到2147483647,这个是与java.lang.Integer对应,其二进制呈现形式和Bytes.toBytes(int)方法产生的一致。 Ø BIGINT:范围为-9223372036854775808 到9223372036854775807 ,与java.lang.Long对应。8个字节,同时也是符号位反转。 Ø UNSIGNED_LONG:可能值为0到9223372036854775807 ,与Bytes.toBytes(long)对应。 Ø TINYINT:-128到127。与java.lang.Byte对应。符号位也需要反转。 Ø UNSIGNED_TINYINT:0到127。二进制表示形式就是一个单字节,和Bytes.toBytes(byte)对应。 Ø SMALLINT:-32768到32767。与java.lang.Short对应。符号位需要反转。 Ø UNSIGNED_SMALLINT:0到32767。二进制表示形式与Bytes.toBytes(short)对应。 Ø FLOAT: -3.402823466 E + 38 到 3.402823466 E + 38,与java.lang.Float对应,首字节需要反转。 Ø UNSIGNED_FLOAT: 0 到 3.402823466 E + 38,二进制表示形式与Bytes.toBytes(float)一致。 Ø DOUBLE:范围为-1.7976931348623158 E + 308 到 1.7976931348623158 E + 308。与java.lang.Double对应,二进制形式首位需反转。 Ø UNSIGNED_DOUBLE: 0到1.7976931348623158 E + 308。二进制表示形式与Bytes.toBytes(double)对应。 Ø DECIMAL:具有固定精度。最大精度为18位,与java.math.BigDecimal对应。其二进制表示形式为可变长度格式。当用于rowkey中,其后会产生一个nullbyte,除非它是最后一列。 Ø BOOLEAN:二进制形式0表示false,1表示true Ø TIME:格式为yyyy-MM-DD hh:mm:ss,具有日期和时间两部分。与java.sql.Time对应。二进制表示形式为8个字节的long型,代表从EPOCH开始的毫秒数 Ø DATE: 格式为yyyy-MM-DD hh:mm:ss,具有日期和时间两部分。与java.sql.DATE对应。二进制表示形式为8个字节的long型,代表从EPOCH开始的毫秒数。 Ø TIMESTAMP:格式为yyyy-MM-dd hh:mm:ss[.nnnnnnnnn],与java.sql.Timestamp,二进制表示为12个字节,8个字节表示long毫秒数,4个字节表示int纳秒数 Ø VARCHAR:具有最大字节长度(可选)的可变长字符串。当用于rowkey时,会在末尾加一个null字节,而如果它正好位于rowkey最后部分则不加。 Ø CHAR:固定长度字符串。二进制表示是UTF8形式与Bytes.toBytes(string)对应。 Ø BINARY:原始固定长度二进制字节数组,与byte[]对应 Ø VARBINARY:原始可变长度二进制格式字节数组。 6 参考网页 HBase 官方:https://hbase.apache.org/ Phoenix 官方:https://github.com/forcedotcom/phoenix Phoenix综述(史上最全Phoenix中文文档) 个人主页:http://www.linbingdong.com 简书地址:http://www.jianshu.com/users/6cb45a00b49c/latest_articles 网上关于Phoenix的资料寥寥无几,中文资料更是几乎没有。本人详细阅读Phoenix官网,整理成此篇中文文档,供后人参考。如有翻译错误的地方,请批评指出。 1. Phoenix定义 Phoenix最早是saleforce的一个开源项目,后来成为Apache基金的顶级项目。 Phoenix是构建在HBase上的一个SQL层,能让我们用标准的JDBC APIs而不是HBase客户端APIs来创建表,插入数据和对HBase数据进行查询。 put the SQL back in NoSQL Phoenix完全使用Java编写,作为HBase内嵌的JDBC驱动。Phoenix查询引擎会将SQL查询转换为一个或多个HBase扫描,并编排执行以生成标准的JDBC结果集。直接使用HBase API、协同处理器与自定义过滤器,对于简单查询来说,其性能量级是毫秒,对于百万级别的行数来说,其性能量级是秒。 HBase的查询工具有很多,如:Hive、Tez、Impala、Spark SQL、Phoenix等。 Phoenix通过以下方式使我们可以少写代码,并且性能比我们自己写代码更好: 将SQL编译成原生的HBase scans。 确定scan关键字的最佳开始和结束 让scan并行执行 ... 使用Phoenix的公司 Paste_Image.png 2. 历史演进 3.0/4.0 release ARRAY Type. 支持标准的JDBC数组类型 Sequences. 支持 CREATE/DROP SEQUENCE, NEXT VALUE FOR, CURRENT VALUE FOR也实现了 Multi-tenancy. 同一张HBase物理表上,不同的租户可以创建相互独立的视图 Views. 同一张HBase物理表上可以创建不同的视图 3.1/4.1 release Apache Pig Loader . 通过pig来处理数据时支持pig加载器来利用Phoenix的性能 Derived Tables. 允许在一个FROM子句中使用SELECT子句来定义一张衍生表 Local Indexing. 后面介绍 Tracing. 后面介绍 3.2/4.2 release Subqueries 支持在WHERE和FROM子句中的独立子查询和相关子查询 Semi/anti joins. 通过标准的[NOT] IN 和 [NOT] EXISTS关键字来支持半/反连接 Optimize foreign key joins. 通过利用跳跃扫描过滤器来优化外键连接 Statistics Collection. 通过收集表的统计信息来提高并行查询能力 3.3/4.3 release Many-to-many joins. 支持两边都太大以至于无法放进内存的连接 Map-reduce Integration. 支持Map-reduce集成 Functional Indexes. 后面介绍 4.4 release User Defined Functions. 后面介绍 4.5 release Asynchronous Index Population. 通过一个Map-reduce job,索引可以被异步创建 4.6 release Time series Optimization. 优化针对时间序列数据的查询 4.7 release Transaction Support. 后面介绍 4.8 release DISTINCT Query Optimization. 使用搜索逻辑来大幅提高 SELECT DISTINCT 和 COUNT DISTINCT的查询性能 Local Index Improvements. Reworked 后面介绍 Hive Integration. 能够在Phoenix内使用Hive来支持大表和大表之间的连接 Namespace Mapping. 将Phoenix schema映射到HBase的命名空间来增强不同schema之间的隔离性 3. 特性 3.1 Transactions (beta) 事务 该特性还处于beta版,并非正式版。通过集成Tephra,Phoenix可以支持ACID特性。Tephra也是Apache的一个项目,是事务管理器,它在像HBase这样的分布式数据存储上提供全局一致事务。HBase本身在行层次和区层次上支持强一致性,Tephra额外提供交叉区、交叉表的一致性来支持可扩展性。 要想让Phoenix支持事务特性,需要以下步骤: 配置客户端hbase-site.xml <property> <name>phoenix.transactions.enabled</name> <value>true</value> </property> 配置服务端hbase-site.xml <property> <name>data.tx.snapshot.dir</name> <value>/tmp/tephra/snapshots</value> </property> <property> <name>data.tx.timeout</name> <value>60</value> <description> set the transaction timeout (time after which open transactions become invalid) to a reasonable value.</description> </property> 配置$HBASE_HOME并启动Tephra ./bin/tephra 通过以上配置,Phoenix已经支持了事务特性,但创建表的时候默认还是不支持的。如果想创建一个表支持事务特性,需要显示声明,如下: CREATE TABLE my_table (k BIGINT PRIMARY KEY, v VARCHAR) TRANSACTIONAL=true; 就是在建表语句末尾增加 TRANSACTIONAL=true。 原本存在的表也可以更改成支持事务的,需要注意的是,事务表无法改回非事务的,因此更改的时候要小心。一旦改成事务的,就改不回去了。 ALTER TABLE my_other_table SET TRANSACTIONAL=true; 3.2 User-defined functions(UDFs) 用户定义函数 3.2.1 概述 Phoenix从4.4.0版本开始支持用户自定义函数。 用户可以创建临时或永久的用户自定义函数。这些用户自定义函数可以像内置的create、upsert、delete一样被调用。临时函数是针对特定的会话或连接,对其他会话或连接不可见。永久函数的元信息会被存储在一张叫做SYSTEM.FUNCTION的系统表中,对任何会话或连接均可见。 3.2.2 配置 hive-site.xml <property> <name>phoenix.functions.allowUserDefinedFunctions</name> <value>true</value> </property> <property> <name>fs.hdfs.impl</name> <value>org.apache.hadoop.hdfs.DistributedFileSystem</value> </property> <property> <name>hbase.rootdir</name> <value>${hbase.tmp.dir}/hbase</value> <description>The directory shared by region servers and into which HBase persists. The URL should be 'fully-qualified' to include the filesystem scheme. For example, to specify the HDFS directory '/hbase' where the HDFS instance's namenode is running at namenode.example.org on port 9000, set this value to: hdfs://namenode.example.org:9000/hbase. By default, we write to whatever ${hbase.tmp.dir} is set too -- usually /tmp -- so change this configuration or else all data will be lost on machine restart.</description> </property> <property> <name>hbase.dynamic.jars.dir</name> <value>${hbase.rootdir}/lib</value> <description> The directory from which the custom udf jars can be loaded dynamically by the phoenix client/region server without the need to restart. However, an already loaded udf class would not be un-loaded. See HBASE-1936 for more details. </description> </property> 后两个配置需要跟hbse服务端的配置一致。 以上配置完后,在JDBC连接时还需要执行以下语句: Properties props = new Properties(); props.setProperty("phoenix.functions.allowUserDefinedFunctions", "true"); Connection conn = DriverManager.getConnection("jdbc:phoenix:localhost", props); 以下是可选的配置,用于动态类加载的时候把jar包从hdfs拷贝到本地文件系统 <property> <name>hbase.local.dir</name> <value>${hbase.tmp.dir}/local/</value> <description>Directory on the local filesystem to be used as a local storage.</description> </property> 3.3 Secondary Indexing 二级索引 在HBase中,只有一个单一的按照字典序排序的rowKey索引,当使用rowKey来进行数据查询的时候速度较快,但是如果不使用rowKey来查询的话就会使用filter来对全表进行扫描,很大程度上降低了检索性能。而Phoenix提供了二级索引技术来应对这种使用rowKey之外的条件进行检索的场景。 Covered Indexes 只需要通过索引就能返回所要查询的数据,所以索引的列必须包含所需查询的列(SELECT的列和WHRER的列) Functional Indexes 从Phoeinx4.3以上就支持函数索引,其索引不局限于列,可以合适任意的表达式来创建索引,当在查询时用到了这些表达式时就直接返回表达式结果 Global Indexes Global indexing适用于多读少写的业务场景。 使用Global indexing的话在写数据的时候会消耗大量开销,因为所有对数据表的更新操作(DELETE, UPSERT VALUES and UPSERT SELECT),会引起索引表的更新,而索引表是分布在不同的数据节点上的,跨节点的数据传输带来了较大的性能消耗。在读数据的时候Phoenix会选择索引表来降低查询消耗的时间。在默认情况下如果想查询的字段不是索引字段的话索引表不会被使用,也就是说不会带来查询速度的提升。 Local Indexes Local indexing适用于写操作频繁的场景。 与Global indexing一样,Phoenix会自动判定在进行查询的时候是否使用索引。使用Local indexing时,索引数据和数据表的数据是存放在相同的服务器中的避免了在写操作的时候往不同服务器的索引表中写索引带来的额外开销。使用Local indexing的时候即使查询的字段不是索引字段索引表也会被使用,这会带来查询速度的提升,这点跟Global indexing不同。一个数据表的所有索引数据都存储在一个单一的独立的可共享的表中。 3.4 Statistics Collection 统计信息收集 UPDATE STATISTICS可以更新某张表的统计信息,以提高查询性能 3.5 Row timestamp 时间戳 从4.6版本开始,Phoenix提供了一种将HBase原生的row timestamp映射到Phoenix列的方法。这样有利于充分利用HBase提供的针对存储文件的时间范围的各种优化,以及Phoenix内置的各种查询优化。 3.6 Paged Queries 分页查询 Phoenix支持分页查询: Row Value Constructors (RVC) OFFSET with limit 3.7 Salted Tables 散步表 如果row key是自动增长的,那么HBase的顺序写会导致region server产生数据热点的问题,Phoenix的Salted Tables技术可以解决region server的热点问题 3.8 Skip Scan 跳跃扫描 可以在范围扫描的时候提高性能 3.9 Views 视图 标准的SQL视图语法现在在Phoenix上也支持了。这使得能在同一张底层HBase物理表上创建多个虚拟表。 3.10 Multi tenancy 多租户 通过指定不同的租户连接实现数据访问的隔离 3.11 Dynamic Columns 动态列 Phoenix 1.2, specifying columns dynamically is now supported by allowing column definitions to included in parenthesis after the table in the FROM clause on a SELECT statement. Although this is not standard SQL, it is useful to surface this type of functionality to leverage the late binding ability of HBase. 3.12 Bulk CSV Data Loading 大量CSV数据加载 加载CSV数据到Phoenix表有两种方式:1. 通过psql命令以单线程的方式加载,数据量少的情况下适用。 2. 基于MapReduce的bulk load工具,适用于数据量大的情况 3.13 Query Server 查询服务器 Phoenix4.4引入的一个单独的服务器来提供thin客户端的连接 3.14 Tracing 追踪 从4.1版本开始Phoenix增加这个特性来追踪每条查询的踪迹,这使用户能够看到每一条查询或插入操作背后从客户端到HBase端执行的每一步。 3.15 Metrics 指标 Phoenix提供各种各样的指标使我们能够知道Phoenix客户端在执行不同SQL语句的时候其内部发生了什么。这些指标在客户端JVM中通过两种方式来收集: Request level metrics - collected at an individual SQL statement level Global metrics - collected at the client JVM level 4. 架构和组成 Phoenix架构 Phoenix Architecture.png Phoenix在Hadoop生态系统中的位置 位置.png 5. 数据存储 Phoenix将HBase的数据模型映射到关系型世界 [图片上传失败...(image-ea505f-1524447379212)] 6. 对QL的支持 支持的命令如下: SELECT Example: SELECT * FROM TEST LIMIT 1000; SELECT * FROM TEST LIMIT 1000 OFFSET 100; SELECT full_name FROM SALES_PERSON WHERE ranking >= 5.0 UNION ALL SELECT reviewer_name FROM CUSTOMER_REVIEW WHERE score >= 8.0 UPSERT VALUES Example: UPSERT INTO TEST VALUES('foo','bar',3); UPSERT INTO TEST(NAME,ID) VALUES('foo',123); UPSERT SELECT Example: UPSERT INTO test.targetTable(col1, col2) SELECT col3, col4 FROM test.sourceTable WHERE col5 < 100 UPSERT INTO foo SELECT * FROM bar; DELETE Example: DELETE FROM TEST; DELETE FROM TEST WHERE ID=123; DELETE FROM TEST WHERE NAME LIKE 'foo%'; CREATE TABLE CREATE TABLE my_schema.my_table ( id BIGINT not null primary key, date) CREATE TABLE my_table ( id INTEGER not null primary key desc, date DATE not null,m.db_utilization DECIMAL, i.db_utilization) m.DATA_BLOCK_ENCODING='DIFF' CREATE TABLE stats.prod_metrics ( host char(50) not null, created_date date not null,txn_count bigint CONSTRAINT pk PRIMARY KEY (host, created_date) ) CREATE TABLE IF NOT EXISTS "my_case_sensitive_table" ( "id" char(10) not null primary key, "value" integer) DATA_BLOCK_ENCODING='NONE',VERSIONS=5,MAX_FILESIZE=2000000 split on (?, ?, ?) CREATE TABLE IF NOT EXISTS my_schema.my_table (org_id CHAR(15), entity_id CHAR(15), payload binary(1000),CONSTRAINT pk PRIMARY KEY (org_id, entity_id) )TTL=86400 DROP TABLE Example: DROP TABLE my_schema.my_table; DROP TABLE IF EXISTS my_table; DROP TABLE my_schema.my_table CASCADE; CREATE FUNCTION Example: CREATE FUNCTION my_reverse(varchar) returns varchar as 'com.mypackage.MyReverseFunction' using jar 'hdfs:/localhost:8080/hbase/lib/myjar.jar' CREATE FUNCTION my_reverse(varchar) returns varchar as 'com.mypackage.MyReverseFunction' CREATE FUNCTION my_increment(integer, integer constant defaultvalue='10') returns integer as 'com.mypackage.MyIncrementFunction' using jar '/hbase/lib/myincrement.jar' CREATE TEMPORARY FUNCTION my_reverse(varchar) returns varchar as 'com.mypackage.MyReverseFunction' using jar 'hdfs:/localhost:8080/hbase/lib/myjar.jar' DROP FUNCTION Example: DROP FUNCTION IF EXISTS my_reverse DROP FUNCTION my_reverse CREATE VIEW Example: CREATE VIEW "my_hbase_table"( k VARCHAR primary key, "v" UNSIGNED_LONG) default_column_family='a'; CREATE VIEW my_view ( new_col SMALLINT ) AS SELECT * FROM my_table WHERE k = 100; CREATE VIEW my_view_on_view AS SELECT * FROM my_view WHERE new_col > 70; DROP VIEW Example: DROP VIEW my_view DROP VIEW IF EXISTS my_schema.my_view DROP VIEW IF EXISTS my_schema.my_view CASCADE CREATE SEQUENCE Example: CREATE SEQUENCE my_sequence; CREATE SEQUENCE my_sequence START WITH -1000 CREATE SEQUENCE my_sequence INCREMENT BY 10 CREATE SEQUENCE my_schema.my_sequence START 0 CACHE 10 DROP SEQUENCE Example: DROP SEQUENCE my_sequence DROP SEQUENCE IF EXISTS my_schema.my_sequence ALTER Example: ALTER TABLE my_schema.my_table ADD d.dept_id char(10) VERSIONS=10 ALTER TABLE my_table ADD dept_name char(50), parent_id char(15) null primary key ALTER TABLE my_table DROP COLUMN d.dept_id, parent_id; ALTER VIEW my_view DROP COLUMN new_col; ALTER TABLE my_table SET IMMUTABLE_ROWS=true,DISABLE_WAL=true; CREATE INDEX Example: CREATE INDEX my_idx ON sales.opportunity(last_updated_date DESC) CREATE INDEX my_idx ON log.event(created_date DESC) INCLUDE (name, payload) SALT_BUCKETS=10 CREATE INDEX IF NOT EXISTS my_comp_idx ON server_metrics ( gc_time DESC, created_date DESC ) DATA_BLOCK_ENCODING='NONE',VERSIONS=?,MAX_FILESIZE=2000000 split on (?, ?, ?) CREATE INDEX my_idx ON sales.opportunity(UPPER(contact_name)) DROP INDEX Example: DROP INDEX my_idx ON sales.opportunity DROP INDEX IF EXISTS my_idx ON server_metrics ALTER INDEX Example: ALTER INDEX my_idx ON sales.opportunity DISABLE ALTER INDEX IF EXISTS my_idx ON server_metrics REBUILD EXPLAIN Example: EXPLAIN SELECT NAME, COUNT(*) FROM TEST GROUP BY NAME HAVING COUNT(*) > 2; EXPLAIN SELECT entity_id FROM CORE.CUSTOM_ENTITY_DATA WHERE organization_id='00D300000000XHP' AND SUBSTR(entity_id,1,3) = '002' AND created_date < CURRENT_DATE()-1; UPDATE STATISTICS Example: UPDATE STATISTICS my_table UPDATE STATISTICS my_schema.my_table INDEX UPDATE STATISTICS my_index UPDATE STATISTICS my_table COLUMNS UPDATE STATISTICS my_table SET phoenix.stats.guidepost.width=50000000 CREATE SCHEMA Example: CREATE SCHEMA IF NOT EXISTS my_schema CREATE SCHEMA my_schema USE Example: USE my_schema USE DEFAULT DROP SCHEMA Example: DROP SCHEMA IF EXISTS my_schema DROP SCHEMA my_schema 7. 安装部署 7.1 安装预编译的Phoenix 下载并解压最新版的phoenix-[version]-bin.tar包 将phoenix-[version]-server.jar放入服务端和master节点的HBase的lib目录下 重启HBase 将phoenix-[version]-client.jar添加到所有Phoenix客户端的classpath 7.2 使用Phoenix 7.2.1 命令行 若要在命令行执行交互式SQL语句: 1.切换到bin目录 2.执行以下语句 $ sqlline.py localhost 若要在命令行执行SQL脚本 $ sqlline.py localhost ../examples/stock_symbol.sql [图片上传失败...(image-f2579c-1524447379209)] 7.2.2 客户端 SQuirrel是用来连接Phoenix的客户端。 SQuirrel安装步骤如下: 1. Remove prior phoenix-[*oldversion*]-client.jar from the lib directory of SQuirrel, copy phoenix-[*newversion*]-client.jar to the lib directory (*newversion* should be compatible with the version of the phoenix server jar used with your HBase installation) 2. Start SQuirrel and add new driver to SQuirrel (Drivers -> New Driver) 3. In Add Driver dialog box, set Name to Phoenix, and set the Example URL to jdbc:phoenix:localhost. 4. Type “org.apache.phoenix.jdbc.PhoenixDriver” into the Class Name textbox and click OK to close this dialog. 5. Switch to Alias tab and create the new Alias (Aliases -> New Aliases) 6. In the dialog box, Name: *any name*, Driver: Phoenix, User Name: *anything*, Password: *anything* 7. Construct URL as follows: jdbc:phoenix: *zookeeper quorum server*. For example, to connect to a local HBase use: jdbc:phoenix:localhost 8. Press Test (which should succeed if everything is setup correctly) and press OK to close. 9. Now double click on your newly created Phoenix alias and click Connect. Now you are ready to run SQL queries against Phoenix. Paste_Image.png 8. 测试 8.1 Pherf Pherf是可以通过Phoenix来进行性能和功能测试的工具。Pherf可以用来生成高度定制的数据集,并且测试SQL在这些数据集上的性能。 8.1.1 构建Pherf Pherf是在用maven构建Phoenix的过程中同时构建的。可以用两种不同的配置来构建: 集群(默认) This profile builds Pherf such that it can run along side an existing cluster. The dependencies are pulled from the HBase classpath. 独立 This profile builds all of Pherf’s dependencies into a single standalone jar. The deps will be pulled from the versions specified in Phoenix’s pom. 构建全部的Phoenix。包含Pherf的默认配置。 mvn clean package -DskipTests 用Pherf的独立配置来构建Phoenix。 mvn clean package -P standalone -DskipTests 8.1.2 安装 用以上的Maven命令构建完Pherf后,会在该模块的目标目录下生成一个zip文件。 将该zip文件解压到合适的目录 配置env.sh文件 ./pherf.sh -h 想要在一个真正的集群上测试,运行如下命令: ./pherf.sh -drop all -l -q -z localhost -schemaFile .*user_defined_schema.sql -scenarioFile .*user_defined_scenario.xml 8.1.3 命令示例 列出所有可运行的场景文件 $./pherf.sh -listFiles 删掉全部场景文件中存在的特定的表、加载和查询数据 $./pherf.sh -drop all -l -q -z localhost 8.1.4 参数 -h Help -l Apply schema and load data -q Executes Multi-threaded query sets and write results -z [quorum] Zookeeper quorum -m Enable monitor for statistics -monitorFrequency [frequency in Ms] _Frequency at which the monitor will snopshot stats to log file. -drop [pattern] Regex drop all tables with schema name as PHERF. Example drop Event tables: -drop .(EVENT). Drop all: -drop .* or -drop all* -scenarioFile Regex or file name of a specific scenario file to run. -schemaFile Regex or file name of a specific schema file to run. -export Exports query results to CSV files in CSV_EXPORT directory -diff Compares results with previously exported results -hint Executes all queries with specified hint. Example SMALL -rowCountOverride -rowCountOverride [number of rows] Specify number of rows to be upserted rather than using row count specified in schema 8.1.5 为数据生成增加规则 8.1.6 定义场景 8.1.7 结果 结果实时写入结果目录中。可以打开.jpg格式文件来实时可视化。 8.1.8 测试 Run unit tests: mvn test -DZK_QUORUM=localhost Run a specific method: mvn -Dtest=ClassName#methodName test More to come... 8.2 性能 Phoenix通过以下方法来奉行把计算带到离数据近的地方的哲学: 协处理器 在服务端执行操作来最小化服务端和客户端的数据传输 定制的过滤器 为了删减数据使之尽可能地靠近源数据并最小化启动代价,Phoenix使用原生的HBase APIs而不是使用Map/Reduce框架 8.2.1 Phoenix对比相近产品 8.2.1.1 Phoenix vs Hive (running over HDFS and HBase) Paste_Image.png Query: select count(1) from table over 10M and 100M rows. Data is 5 narrow columns. Number of Region Servers: 4 (HBase heap: 10GB, Processor: 6 cores @ 3.3GHz Xeon) 8.2.1.2 Phoenix vs Impala (running over HBase) Paste_Image.png Query: select count(1) from table over 1M and 5M rows. Data is 3 narrow columns. Number of Region Server: 1 (Virtual Machine, HBase heap: 2GB, Processor: 2 cores @ 3.3GHz Xeon) 8.2.2 Latest Automated Performance Run Latest Automated Performance Run | Automated Performance Runs History 8.2.3 Phoenix1.2性能提升 Essential Column Family Paste_Image.png Skip Scan Paste_Image.png Salting Paste_Image.png Top-N Paste_Image.png 9. 参考资料 http://phoenix.apache.org http://phoenix.apache.org/Phoenix-in-15-minutes-or-less.html http://hadooptutorial.info/apache-phoenix-hbase-an-sql-layer-on-hbase/ http://www.phoenixframework.org/docs/resources https://en.wikipedia.org/wiki/Apache_Phoenix

优秀的个人博客,低调大师

Gradle学习之部署上传项目

原先在公司做项目时,写了一个简单的基于gradle部署项目的脚本,今天翻出来记录一下 一、build.gradle buildscript { ext { env = System.getProperty("env") ?: "test" jvmArgs = "-server -Xms128m -Xmx128m -XX:NewRatio=4 -XX:SurvivorRatio=16 -XX:MaxTenuringThreshold=15 -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+ExplicitGCInvokesConcurrent -XX:+DoEscapeAnalysis -XX:-HeapDumpOnOutOfMemoryError" if (env == "prod") { jvmArgs = "-server -Xms2g -Xmx2g -XX:NewRatio=4 -XX:SurvivorRatio=16 -XX:MaxTenuringThreshold=15 -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+ExplicitGCInvokesConcurrent -XX:+DoEscapeAnalysis -XX:-HeapDumpOnOutOfMemoryError" } userHome = System.getProperty("user.home") osName = System.getProperty("os.name") } repositories { jcenter() } dependencies { classpath 'org.hidetake:gradle-ssh-plugin:2.7.0' classpath 'co.tomlee.gradle.plugins:gradle-thrift-plugin:0.0.6' } } allprojects { apply plugin: 'idea' apply plugin: 'eclipse' apply plugin: 'org.hidetake.ssh' group = 'com.mwee.information.core' version = '1.0-SNAPSHOT' ssh.settings { timeoutSec = 60 knownHosts = allowAnyHosts } defaultTasks 'clean', 'copyPartDependencies' //排除Log4j依赖 configurations { compile.exclude module: 'slf4j-log4j12' compile.exclude module: 'org.apache.logging.log4j' compile.exclude module: 'log4j' all*.exclude group: 'org.apache.logging.log4j' all*.exclude group: 'log4j' } } subprojects { apply plugin: 'java' sourceCompatibility = 1.8 targetCompatibility = 1.8 repositories { mavenLocal() maven { url "http://114.80.88.52:9001/nexus/content/groups/public/" } } sourceSets { main { java { srcDirs = ['src/main/java'] } resources { srcDirs = ["src/main/resources", "src/main/profile/$env"] } } } dependencies { compile("org.codehaus.groovy:groovy-all:2.2.1") compile 'org.codehaus.groovy:groovy-backports-compat23:2.4.5' compile("org.springframework.boot:spring-boot-starter-web:1.4.2.RELEASE") compile("org.apache.commons:commons-lang3:3.4") compile("org.apache.commons:commons-collections4:4.1") compile "org.apache.commons:commons-pool2:2.4.2" compile group: 'com.alibaba', name: 'fastjson', version: '1.2.12' // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.8.6' // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.8.6' compile group: 'org.aspectj', name: 'aspectjrt', version: '1.8.7' compile group: 'org.aspectj', name: 'aspectjweaver', version: '1.8.7' compile group: 'com.thoughtworks.xstream', name: 'xstream', version: '1.4.1' compile(group: 'org.mortbay.jetty', name: 'jetty', version: '6.1.26') compile group: 'org.projectlombok', name: 'lombok', version: '1.16.8' compile group: 'com.squareup.okhttp', name: 'okhttp', version: '2.7.5' compile group: 'com.google.guava', name: 'guava', version: '18.0' compile group: 'commons-lang', name: 'commons-lang', version: '2.6' compile group: 'com.jcraft', name: 'jsch', version: '0.1.53' testCompile group: 'junit', name: 'junit', version: '4.12' testCompile "org.springframework:spring-test:4.3.4.RELEASE" compile "javax.validation:validation-api:1.1.0.Final" compile "org.hibernate:hibernate-validator:5.2.4.Final" } //gradle utf-8 compile tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } task copyAllDependencies(type: Copy, dependsOn: jar) { description = "拷贝全部依赖的jar包" from configurations.runtime into 'build/libs' } task copyPartDependencies(type: Copy, dependsOn: jar) { description = "拷贝部分依赖的jar" from configurations.runtime into 'build/libs' doLast { file("build/libs").listFiles({ !it.name.endsWith("-SNAPSHOT.jar") } as FileFilter).each { it.delete() } } } } View Code 二、对应模块下的build.gradle def mainClass = "com.hzgj.information.rest.user.run.UserServiceProvider" def appHome = "/home/appsvr/apps/rest_user" def javaCommand = "nohup java $jvmArgs -Djava.ext.dirs=$appHome/libs -Denv=$env $mainClass >$appHome/shell.log 2>&1 &" def index = System.getProperty("index") def remote = remotes { test_0 { role 'test_0' host = '10.0.21.152' if (file("$userHome/.ssh/id_rsa").exists()) { user = 'appsvr' identity = file("$userHome/.ssh/id_rsa") } else { user = 'appsvr' password = 'xxx' } } test_1 { role 'test_1' host = '10.0.146.20' if (file("$userHome/.ssh/id_rsa").exists()) { user = 'appsvr' identity = file("$userHome/.ssh/id_rsa") } else { user = 'appsvr' password = 'xxx' } } home { role 'home' host = '192.168.109.130' user = 'appsvr' password = 'xxx' // identity = file('id_rsa') } } task deploy << { description = "拷贝jar包并启动java服务" def roles = remote.findAll { def currentEnv = index == null ? "$env" : "$env" + "_" + index it['roles'][0].toString().contains(currentEnv) } ssh.run { roles.each { def role = it['roles'][0].toString() session(remotes.role(role)) { try { execute("ls $appHome") } catch (Exception e) { println("#############目录[$appHome]不存在,将自动创建############") execute("mkdir -p $appHome") } finally { def r = '$1' def pid = execute("jps -l |grep '$mainClass' |awk \'{print $r}\'") if (pid) { execute("kill -9 $pid") } put from: 'build/libs', into: "$appHome" println("###############准备启动java服务[$javaCommand]####################") execute("$javaCommand") sleep(10000) pid = execute("jps -l |grep '$mainClass' |awk \'{print $r}\'") if (pid) { println("#####$mainClass [$pid] 启动成功...######") execute("rm -f $appHome/shell.log") } else { println("#$mainClass 启动失败...输出日志如下:#") execute("cat $appHome/shell.log") } } } } } } task stop << { def roles = remote.findAll { def currentEnv = index == null ? "$env" : "$env" + "_" + index it['roles'][0].toString().contains(currentEnv) } ssh.run { roles.each { session(remotes.role("$env")) { def r = '$1' def pid = execute("jps -l |grep '$mainClass' |awk \'{print $r}\'") if (pid) { execute("kill -9 $pid") } } } } } task start << { def roles = remote.findAll { def currentEnv = index == null ? "$env" : "$env" + "_" + index it['roles'][0].toString().contains(currentEnv) } ssh.run { roles.each { def role = it['roles'][0].toString() session(remotes.role(role)) { def r = '$1' def pid = execute("jps -l |grep '$mainClass' |awk \'{print $r}\'") if (pid) { execute("kill -9 $pid") } println("###############准备启动java服务[$javaCommand]####################") execute("$javaCommand") sleep(10000) pid = execute("jps -l |grep '$main Class' |awk \'{print $r}\'") if (pid) { println("#$mainClass [$pid] 启动成功...#") execute("rm -f $appHome/shell.log") } else { println("#$mainClass 启动失败...输出日志如下:#") execute("cat $appHome/shell.log") } } } } } View Code 三、使用方式 1.先运行gradle copyAll -x test 进行打包操作,该操作会将该模块所有的依赖的jar 2.进入到对应的模块下 运行gradle deploy -Denv=xxx -Dindex=xxx ,什么意思呢?-Denv代表哪一个环境 -Dindex指定该环境下哪个节点进行发布 3.gradle start -Denv=xxx -Dindex=xxx 运行当前环境下的应用

优秀的个人博客,低调大师

实战深度学习(下)OpenCV库

在上一节中,我们讲到了OpenCV库的安装,现在我们来进行实战,看如何利用Python来调用OpenCV库。 一: 如果您的电脑是win10的系统,那么请您按下win键,再按下空格键,输入Python,进入Python的IDEA shell界面。这个时候您也可以直接进入CMD进行民命令行模式的编辑,因为第一次可我们并不会很多的代码需要您去编辑。在后期您可以使用轻量级的IDEA,比如sublime test3 或者重量级的Pycharm IDEA进行编辑,它们都是现在世界上十分常用的Python编译器,用它们进行编辑,会给你们一种视觉上的清新之感以及灵魂上的愉悦之感呢。 二:如果您的电脑是linux操作系统,这是一个主流的选择。很好,笔者现在还没有为我的linux操作系统配置上Python环境,因此具体方法您可以百度一下。 三:如果您的电脑是苹果电脑,请您赶紧卖了,因为配置太低,系统难用,价格昂贵。完全不适合编写程序搞事情。 四:开始编写代码: 现在我们输入以下代码: import cv2 #表示您引入了opencv库 import numpy as np #表示您引入了用于计算矩阵的库并且将numpy简写为了np 现在,如果您按下F5运行,编译器没有报错的话,那么把您的库文件肯定是安装好的了,嘿嘿 五:读入图片,保存图片: 在opencv库当中,最基本的一步就是读入图片和保存图片了。我们可以在读入和保存图片的时候改变图片的格式,因为里面的库函数对Python的文件读写已经进行了一定的操作。现在我们键入以下代码: # Load an color image in grayscale img = cv2.imread('呵呵.jpg',0) #表示您所读入的图片的名称和路径 cv2.imshow('image',img) #显示图像 cv2.waitKey(0) #等待键盘事件,这和我们的单片机相同 cv2.destroyAllWindows() #意思和上面的英文代码相同 六:保存图片文件: 请输入以下代码: cv2.imwrite('呵呵.png',img) #即可保存以上图片为png格式了,十分方便。 七,笔者已经自己用OpenCV尝试成功进行人脸识别的项目,其结果如下所示:(由于这是在我的公众号上复制的,本人性别男,性格:懒。因此就懒得把图片复制过来了额)

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册