个人统计

用户名: 没楼可以吗
等级: 初来乍到
威望: 0
在线时间: 4 小时
日志总数: 376
评论数量: 16
访问次数: 217361
建立时间: 2004-04-28
RSS订阅       手机访问

博主资料

留言短消息 加为好友 收藏

用户ID:  41
昵称:  没楼可以吗
来自:  山东 聊城
年龄:  保密

日历

2018 - 9
      1
2345678
9101112131415
16171819202122
23242526272829
30      
«» 2018 - 9 «»

最近访问

日志分类

圈子信息

好友(0)

首页 前页 后页 尾页
1页,共 0 页

日志文章列表

2018年07月18日 14:58:11

Nginx的 HTTP 499 状态码处理

1、前言

  今天在处理一个客户问题,遇到Nginx access log中出现大量的499状态码。实际场景是:客户的域名通过cname解析到我们的Nginx反向代理集群上来,客户的Web服务是由一个负载均衡提供外网IP进行访问,负载均衡后面挂了多个内网web站点业务服务器。出现的访问日志如下所示:



2、处理方法

    499错误是什么?让我们看看NGINX的源码中的定义:
  ngx_string(ngx_http_error_495_page), /* 495, https certificate error */
  ngx_string(ngx_http_error_496_page), /* 496, https no certificate */
  ngx_string(ngx_http_error_497_page), /* 497, http to https */
  ngx_string(ngx_http_error_404_page), /* 498, canceled */
  ngx_null_string,                    /* 499, client has closed connection */

     可以看到,499对应的是 “client has closed connection”。这很有可能是因为服务器端处理的时间过长,客户端“不耐烦”了。

      测试nginx发现如果两次提交post过快就会出现499的情况,看来是nginx认为是不安全的连接,主动拒绝了客户端的连接.

      在google上搜索到一英文论坛上有关于此错误的解决方法:
      proxy_ignore_client_abort on;
      Don’t know if this is safe.
      就是说要配置参数 proxy_ignore_client_abort on;
      表示代理服务端不要主要主动关闭客户端连接。

      以此配置重启nginx,问题果然得到解决。只是安全方面稍有欠缺,但比总是出现找不到服务器好多了。

类别: 无分类 |  评论(0) |  浏览(39) |  收藏
2018年06月25日 15:42:15

syntax error, unexpected '[', expecting ')' php版本低不支持数组写法

因为服务器安装的是PHP5.2,所以选用Thinkphp3.1.3,在本地测试没问题,部署到服务器上就报已下错误
具体报错:Parse error: syntax error, unexpected '[', expecting ')' in /www/web/hrly/public_html/hrly/App/Common/common.php on line 14


【答】

你的PHP 版本是5.2的 你的数组写法却是5.4的 5.2中用array() 不能用[]

楼上正解 [](5.4版本以上) => array()

类别: 无分类 |  评论(0) |  浏览(52) |  收藏
2018年05月20日 23:25:16

innodb log file size 配置估算以及修改


root@localhost:(none) 06:22:17>pager grep seq
PAGER set to 'grep seq'


root@localhost:(none) 06:30:33>show engine innodb status\G select sleep(60); show engine innodb status\G
Log sequence number 29532909727
1 row in set (0.00 sec)
1 row in set (1 min 0.00 sec)
Log sequence number 29641344616
1 row in set (0.01 sec)


root@localhost:(none) 06:32:03>nopager
PAGER set to stdout


root@localhost:(none) 06:32:17>select (29641344616-29532909727)60/1024/1024
-> ;
+----------------------------------------+
| (29641344616-29532909727)60/1024/1024 |
+----------------------------------------+
| 6204.69411850 |
+----------------------------------------+
1 row in set (0.00 sec)


MySQL5.7 修改my.cnf重启即可
小于MySQL5.7
1.修改 my.cnf: innodb_log_file_size
2.stop MySQL server
3.确保MySQL干净的停止
4.删除旧的log files
5.启动MySQL server

类别: 无分类 |  评论(0) |  浏览(75) |  收藏
2018年05月20日 09:14:05

ip段/数字,如192.168.0.1/24是什么意思?

ip段/数字,如192.168.0.1/24是什么意思?
2014年09月19日 12:17:24 阅读数:185706 网上到处可见IP字段/数字, 例如: 192.168.0.1/24 是什么意思?
首先来了解一下二进制的转换知识:

二进制数转换成十进制数 二进制的1101转化成十进制
1101(2)=1*2^0+0*2^1+1*2^2+1*2^3=1+0+4+8=13
转化成十进制要从右到左用二进制的每个数去乘以2的相应次方.
不过次方要从0开始
相反 用十进制的13除以2 每除一下将余数就记在旁边
最后按余数从下向上排列就可得到1101
十进制转二进制:

用2辗转相除至结果为1
将余数和最后的1从下向上倒序写 就是结果
例如302
302/2 = 151 余0
151/2 = 75 余1
75/2 = 37 余1
37/2 = 18 余1
18/2 = 9 余0
9/2 = 4 余1
4/2 = 2 余0
2/2 = 1 余0
1/2 = 0 余1
故二进制为100101110
子网掩码的前缀表示法!  11111111 11111111 1111111 00000000  24个1组成    转成成十进制等于 255.255.255.0    11111111 11111111 1111111 11111100  30个1组成    转成成十进制等于 255.255.255.252 [/pre]我们租用服务器/vps的时候,买多个IP地址,机房总是发一个类似 10.0.0.1/29 或 10.0.0.1/28 或 10.0.0.1/30 或 10.0.0.1/27 的地址给我们,对于不熟悉网络的人来说,真的莫名其妙。到底有哪些可用的IP? 网关,子网掩码,广播地址是什么?
为了方便大家,本文章提供了 可用IP查询,ip段/27 /29 /30 网关,子网掩码,广播地址查询
可用IP查询,IP段对应表

IP总数子网掩码C段个数/30/29/28/27/26/24/23/22/21/20/19/18/17/16
4255.255.255.2521/64
8255.255.255.2481/32
16255.255.255.2401/16
32255.255.255.2241/8
64255.255.255.1921/4
256255.255.255.01
512255.255.254.02
1024255.255.252.04
2048255.255.248.08
4096255.255.240.016
8192255.255.224.032
16384255.255.192.064
32768255.255.128.0128
65536255.255.0.0256

ip段/24 /25 /26 /27 /28 /29 /30
网关,子网掩码,广播地址查询
范例: 要查询204.45.116.184/29,先找到下表的 /29 表格,网关 这一列找到要查询的IP最后一位即.184,然后就可以看到可用IP范围(注:第一个IP是Gateway网关地址)和广播地址了。然后从上面的表找到 子网掩码即可。
/25 — 2 Subnets — 126 Hosts/Subnet
网络地址可用IP范围广播地址
.0.1-.126.127
.128.129-.254.255
/24 –1 Subnets – 254 Hosts/Subnet
代表一整个C段
网络地址可用IP范围广播地址
.0.1-.254.255
/30 — 64 Subnets — 2 Hosts/Subnet
网络地址可用IP范围广播地址
.0.1-.2.3
.4.5-.6.7
.8.9-.10.11
.12.13-.14.15
.16.17-.18.19
.20.21-.22.23
.24.25-.26.27
.28.29-.30.31
.32.33-.34.35
.36.37-.38.39
.40.41-.42.43
.44.45-.46.47
.48.49-.50.51
.52.53-.54.55
.56.57-.58.59
.60.61-.62.63
.64.65-.66.67
.68.69-.70.71
.72.73-.74.75
.76.77-.78.79
.80.81-.82.83
.84.85-.86.87
.88.89-.90.91
.92.93-.94.95
.96.97-.98.99
.100.101-.102.103
.104.105-.106.107
.108.109-.110.111
.112.113-.114.115
.116.117-.118.119
.120.121-.122.123
.124.125-.126.127
.128.129-.130.131
.132.133-.134.135
.136.137-.138.139
.140.141-.142.143
.144.145-.146.147
.148.149-.150.151
.152.153-.154.155
.156.157-.158.159
.160.161-.162.163
.164.165-.166.167
.168.169-.170.171
.172.173-.174.175
.176.177-.178.179
.180.181-.182.183
.184.185-.186.187
.188.189-.190.191
.192.193-.194.195
.196.197-.198.199
.200.201-.202.203
.204.205-.206.207
.208.209-.210.211
.212.213-.214.215
.216.217-.218.219
.220.221-.222.223
.224.225-.226.227
.228.229-.230.231
.232.233-.234.235
.236.237-.238.239
.240.241-.242.243
.244.245-.246.247
.248.249-.250.251
.252.253-.254.255
/26 — 4 Subnets — 62 Hosts/Subnet
网络地址可用IP范围广播地址
.0.1-.62.63
.64.65-.126.127
.128.129-.190.191
.192.193-.254.255
/27 — 8 Subnets — 30 Hosts/Subnet
网络地址可用IP范围广播地址
.0.1-.30.31
.32.33-.62.63
.64.65-.94.95
.96.97-.126.127
.128.129-.158.159
.160.161-.190.191
.192.193-.222.223
.224.225-.254.255
/28 — 16 Subnets — 14 Hosts/Subnet
网络地址可用IP范围广播地址
.0.1-.14.15
.16.17-.30.31
.32.33-.46.47
.48.49-.62.63
.64.65-.78.79
.80.81-.94.95
.96.97-.110.111
.112.113-.126.127
.128.129-.142.143
.144.145-.158.159
.160.161-.174.175
.176.177-.190.191
.192.193-.206.207
.208.209-.222.223
.224.225-.238.239
.240.241-.254.255
/29 — 32 Subnets — 6 Hosts/Subnet
网络地址可用IP范围广播地址
.0.1-.6.7
.8.9-.14.15
.16.17-.22.23
.24.25-.30.31
.32.33-.38.39
.40.41-.46.47
.48.49-.54.55
.56.57-.62.63
.64.65-.70.71
.72.73-.78.79
.80.81-.86.87
.88.89-.94.95
.96.97-.102.103
.104.105-.110.111
.112.113-.118.119
.120.121-.126.127
.128.129-.134.135
.136.137-.142.143
.144.145-.150.151
.152.153-.158.159
.160.161-.166.167
.168.169-.174.175
.176.177-.182.183
.184.185-.190.191
.192.193-.198.199
.200.201-.206.207
.208.209-.214.215
.216.217-.222.223
.224.225-.230.231
.232.233-.238.239
.240.241-.246.247
.248.249-.254.255



类别: 无分类 |  评论(0) |  浏览(110) |  收藏
2018年05月15日 16:03:21

How to calculate a good InnoDB log file size

How to calculate a good InnoDB log file size
Baron Schwartz | November 21, 2008 |  Posted In: Insight for DBAs

https://www.percona.com/blog/2008/11/21/how-to-calculate-a-good-innodb-log-file-size/

PREVIOUS POST NEXT POST
Peter wrote a post a while ago about choosing a good InnoDB log file size. Not to pick on Peter, but the post actually kind of talks about a lot of things and then doesn’t tell you how to choose a good log file size! So I thought I’d clarify it a little.

The basic point is that your log file needs to be big enough to let InnoDB optimize its I/O, but not so big that recovery takes a long time. That much Peter covered really well. But how do you choose that size? I’ll show you a rule of thumb that works pretty well.


In most cases, when people give you a formula for choosing a configuration setting, you should look at it with skepticism. But in this case you can calculate a reasonable value, believe it or not. Run these queries at your server’s peak usage time:

mysql> pager grep sequence
PAGER set to 'grep sequence'
mysql> show engine innodb statusG select sleep(60); show engine innodb statusG
Log sequence number 84 3836410803
1 row in set (0.06 sec)
1 row in set (1 min 0.00 sec)
Log sequence number 84 3838334638
1 row in set (0.05 sec)

Notice the log sequence number. That’s the total number of bytes written to the transaction log. So, now you can see how many MB have been written to the log in one minute. (The technique I showed here works on all versions of MySQL. In 5.0 and newer, you can just watch Innodb_os_log_written from SHOW GLOBAL STATUS, too.)

mysql> select (3838334638 - 3836410803) / 1024 / 1024 as MB_per_min;
+------------+
| MB_per_min |
+------------+
| 1.83471203 |
+------------+

As a rough rule of thumb, you can make the log big enough that it can hold at most an hour or so of logs. That’s generally plenty of data for InnoDB to work with; an hour’s worth is more than enough so that it can reorder the writes to use sequential I/O during the flushing and checkpointing process. At this rate, this server could use about 110 MB of logs, total. Round it up to 128 for good measure. Since there are two log files by default, divide that in half, and now you can set

innodb_log_file_size=64M

Does that look surprisingly small? It might. I commonly see log file sizes in the gigabyte ranges. But that’s generally a mistake. The server I used for the measurements above is a big one doing a lot of work, not a toy. Log file sizes can’t be left at the default 5MB for any real workload, but they often don’t need to be as big as you might think, either.

If this rule-of-thumb calculation ends up showing you that your log file size ought to be many gigabytes, well, you have a more active write workload. Perhaps you’re inserting a lot of big rows or something. In this case you might want to make the log smaller so you don’t end up with GB of logs. But also realize this: the recovery time depends not only on the total log file size, but the number of entries in it. If you’re writing huge entries to the log, fewer log entries will fit into a given log file size, which will generally make recovery faster than you might expect with a big log.

However, most of the time when I run this calculation, I end up finding that the log file size needs to be a lot smaller than it’s configured to be. In part that’s because InnoDB’s log entries are very compact. The other reason is that the common advice to size the logs as a fraction of the buffer pool size is just wrong.

One final note: huge buffer pools or really unusual workloads may require bigger (or smaller!) log sizes. This is where formulas break down and judgment and experience are needed. But this “rule of thumb” is generally a good sane place to start.

类别: 无分类 |  评论(0) |  浏览(83) |  收藏
2018年05月15日 15:34:09

Galera / MySQL: log block numbers mismatch

https://dba.stackexchange.com/questions/132409/galera-replication-error-log-block-numbers-mismatch

[Q]

I am attempting to get Galera replication working between two nodes.

I am finding these errors in my innobackup.backup.log file:

xtrabackup: error: log block numbers mismatch:
xtrabackup: error: expected log block no. 671400745, but got no. 679592737 from the log file.
xtrabackup: error: it looks like InnoDB log has wrapped around before xtrabackup could process all records due to either log copying being too slow, or log files being too small.
xtrabackup: Error: xtrabackup_copy_logfile() failed.

I am not sure where to do from here, I have googled a bit and didn't find anything that seemed like it could help me in my particular instance.

Any advice will be most appreciated.

[A]

I finally have solved this problem.

I found an article on launchpad that said to use this command to see if the problem was IO:
innobackupex --user=<username> --password=<password> --stream=tar -- ibbackup=/usr/bin/xtrabackup /tmp >/dev/null

This failed to, so I started thinking IO was not at fault.

I played around with this command and found this one to complete:
innobackupex --user=<username> --password=<password> --stream=xbstream --parallel=15 /tmp >/dev/null

This also showed that my ulimit was not high enough, so I had to set this higher for the backup to complete.

To force innobackupex to use xbstream instead of tar for the --stream option I but this in my.cnf on both of my galera servers:
[sst] streamfmt=xbstream

类别: 无分类 |  评论(3) |  浏览(217) |  收藏
2018年05月15日 15:28:02

Android数据存储五种方式总结

https://www.cnblogs.com/ITtangtang/p/3920916.html


本文介绍Android平台进行数据存储的五大方式,分别如下: 

    1 使用SharedPreferences存储数据

    2 文件存储数据     

    3 SQLite数据库存储数据

    4 使用ContentProvider存储数据

    5 网络存储数据

下面详细讲解这五种方式的特点

第一种: 使用SharedPreferences存储数据

    适用范围:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。比如应用程序的各种配置信息(如是否打开音效、是否使用震动效果、小游戏的玩家积分等),解锁口 令密码等

    核心原理:保存基于XML文件存储的key-value键值对数据,通常用来存储一些简单的配置信息。通过DDMS的File Explorer面板,展开文件浏览树,很明显SharedPreferences数据总是存储在/data/data/<package name>/shared_prefs目录下。SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过SharedPreferences.edit()获取的内部接口Editor对象实现。 SharedPreferences本身是一 个接口,程序无法直接创建SharedPreferences实例,只能通过Context提供的getSharedPreferences(String name, int mode)方法来获取SharedPreferences实例,该方法中name表示要操作的xml文件名,第二个参数具体如下:

                Context.MODE_PRIVATE: 指定该SharedPreferences数据只能被本应用程序读、写。

                Context.MODE_WORLD_READABLE:  指定该SharedPreferences数据能被其他应用程序读,但不能写。

                Context.MODE_WORLD_WRITEABLE:  指定该SharedPreferences数据能被其他应用程序读,写

Editor有如下主要重要方法:

                SharedPreferences.Editor clear():清空SharedPreferences里所有数据

                SharedPreferences.Editor putXxx(String key , xxx value): 向SharedPreferences存入指定key对应的数据,其中xxx 可以是boolean,float,int等各种基本类型据

                SharedPreferences.Editor remove(): 删除SharedPreferences中指定key对应的数据项

                boolean commit(): 当Editor编辑完成后,使用该方法提交修改

    实际案例:运行界面如下

                     

这里只提供了两个按钮和一个输入文本框,布局简单,故在此不给出界面布局文件了,程序核心代码如下:       

class ViewOcl implements View.OnClickListener{

        @Override
        public void onClick(View v) {

            switch(v.getId()){
            case R.id.btnSet:
                //步骤1:获取输入值
                String code = txtCode.getText().toString().trim();
                //步骤2-1:创建一个SharedPreferences.Editor接口对象,lock表示要写入的XML文件名,MODE_WORLD_WRITEABLE写操作
                SharedPreferences.Editor editor = getSharedPreferences("lock", MODE_WORLD_WRITEABLE).edit();
                //步骤2-2:将获取过来的值放入文件
                editor.putString("code", code);
                //步骤3:提交
                editor.commit();
                Toast.makeText(getApplicationContext(), "口令设置成功", Toast.LENGTH_LONG).show();
                break;
            case R.id.btnGet:
                //步骤1:创建一个SharedPreferences接口对象
                SharedPreferences read = getSharedPreferences("lock", MODE_WORLD_READABLE);
                //步骤2:获取文件中的值
                String value = read.getString("code", "");
                Toast.makeText(getApplicationContext(), "口令为:"+value, Toast.LENGTH_LONG).show();
               
                break;
               
            }
        }
       
    }读写其他应用的SharedPreferences: 步骤如下

                1、在创建SharedPreferences时,指定MODE_WORLD_READABLE模式,表明该SharedPreferences数据可以被其他程序读取

                2、创建其他应用程序对应的Context:

                    Context pvCount = createPackageContext("com.tony.app", Context.CONTEXT_IGNORE_SECURITY);这里的com.tony.app就是其他程序的包名

                3、使用其他程序的Context获取对应的SharedPreferences

                    SharedPreferences read = pvCount.getSharedPreferences("lock", Context.MODE_WORLD_READABLE);

                4、如果是写入数据,使用Editor接口即可,所有其他操作均和前面一致。

SharedPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其职能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。



第二种: 文件存储数据

核心原理: Context提供了两个方法来打开数据文件里的文件IO流 FileInputStream openFileInput(String name); FileOutputStream(String name , int mode),这两个方法第一个参数 用于指定文件名,第二个参数指定打开文件的模式。具体有以下值可选:

            MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可  以使用Context.MODE_APPEND

            MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。

            MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;

            MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。

除此之外,Context还提供了如下几个重要的方法:

            getDir(String name , int mode):在应用程序的数据文件夹下获取或者创建name对应的子目录

            File getFilesDir():获取该应用程序的数据文件夹得绝对路径

            String[] fileList():返回该应用数据文件夹的全部文件             

实际案例:界面沿用上图

            核心代码如下:

public String read() {
        try {
            FileInputStream inStream = this.openFileInput("message.txt");
            byte[] buffer = new byte[1024];
            int hasRead = 0;
            StringBuilder sb = new StringBuilder();
            while ((hasRead = inStream.read(buffer)) != -1) {
                sb.append(new String(buffer, 0, hasRead));
            }

            inStream.close();
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
   
    public void write(String msg){
        // 步骤1:获取输入值
        if(msg == null) return;
        try {
            // 步骤2:创建一个FileOutputStream对象,MODE_APPEND追加模式
            FileOutputStream fos = openFileOutput("message.txt",
                    MODE_APPEND);
            // 步骤3:将获取过来的值放入文件
            fos.write(msg.getBytes());
            // 步骤4:关闭数据流
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }openFileOutput()方法的第一参数用于指定文件名称,不能包含路径分隔符“/” ,如果文件不存在,Android 会自动创建它。创建的文件保存在/data/data/<package name>/files目录,如: /data/data/cn.tony.app/files/message.txt,

下面讲解某些特殊文件读写需要注意的地方:

读写sdcard上的文件

其中读写步骤按如下进行:

1、调用Environment的getExternalStorageState()方法判断手机上是否插了sd卡,且应用程序具有读写SD卡的权限,如下代码将返回true

Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)

2、调用Environment.getExternalStorageDirectory()方法来获取外部存储器,也就是SD卡的目录,或者使用"/mnt/sdcard/"目录

3、使用IO流操作SD卡上的文件

注意点:手机应该已插入SD卡,对于模拟器而言,可通过mksdcard命令来创建虚拟存储卡

          必须在AndroidManifest.xml上配置读写SD卡的权限

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

案例代码:

// 文件写操作函数
    private void write(String content) {
        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) { // 如果sdcard存在
            File file = new File(Environment.getExternalStorageDirectory()
                    .toString()
                    + File.separator
                    + DIR
                    + File.separator
                    + FILENAME); // 定义File类对象
            if (!file.getParentFile().exists()) { // 父文件夹不存在
                file.getParentFile().mkdirs(); // 创建文件夹
            }
            PrintStream out = null; // 打印流对象用于输出
            try {
                out = new PrintStream(new FileOutputStream(file, true)); // 追加文件
                out.println(content);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (out != null) {
                    out.close(); // 关闭打印流
                }
            }
        } else { // SDCard不存在,使用Toast提示用户
            Toast.makeText(this, "保存失败,SD卡不存在!", Toast.LENGTH_LONG).show();
        }
    }

    // 文件读操作函数
    private String read() {

        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) { // 如果sdcard存在
            File file = new File(Environment.getExternalStorageDirectory()
                    .toString()
                    + File.separator
                    + DIR
                    + File.separator
                    + FILENAME); // 定义File类对象
            if (!file.getParentFile().exists()) { // 父文件夹不存在
                file.getParentFile().mkdirs(); // 创建文件夹
            }
            Scanner scan = null; // 扫描输入
            StringBuilder sb = new StringBuilder();
            try {
                scan = new Scanner(new FileInputStream(file)); // 实例化Scanner
                while (scan.hasNext()) { // 循环读取
                    sb.append(scan.next() + "\n"); // 设置文本
                }
                return sb.toString();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (scan != null) {
                    scan.close(); // 关闭打印流
                }
            }
        } else { // SDCard不存在,使用Toast提示用户
            Toast.makeText(this, "读取失败,SD卡不存在!", Toast.LENGTH_LONG).show();
        }
        return null;
    } 第三种:SQLite存储数据

SQLite是轻量级嵌入式数据库引擎,它支持 SQL 语言,并且只利用很少的内存就有很好的性能。现在的主流移动设备像Android、iPhone等都使用SQLite作为复杂数据的存储引擎,在我们为移动设备开发应用程序时,也许就要使用到SQLite来存储我们大量的数据,所以我们就需要掌握移动设备上的SQLite开发技巧

SQLiteDatabase类为我们提供了很多种方法,上面的代码中基本上囊括了大部分的数据库操作;对于添加、更新和删除来说,我们都可以使用

1 db.executeSQL(String sql); 
2 db.executeSQL(String sql, Object[] bindArgs);//sql语句中使用占位符,然后第二个参数是实际的参数集 除了统一的形式之外,他们还有各自的操作方法:

1 db.insert(String table, String nullColumnHack, ContentValues values); 
2 db.update(String table, Contentvalues values, String whereClause, String whereArgs); 
3 db.delete(String table, String whereClause, String whereArgs);以上三个方法的第一个参数都是表示要操作的表名;insert中的第二个参数表示如果插入的数据每一列都为空的话,需要指定此行中某一列的名称,系统将此列设置为NULL,不至于出现错误;insert中的第三个参数是ContentValues类型的变量,是键值对组成的Map,key代表列名,value代表该列要插入的值;update的第二个参数也很类似,只不过它是更新该字段key为最新的value值,第三个参数whereClause表示WHERE表达式,比如“age > ? and age < ?”等,最后的whereArgs参数是占位符的实际参数值;delete方法的参数也是一样

下面给出demo

数据的添加

1.使用insert方法

1 ContentValues cv = new ContentValues();//实例化一个ContentValues用来装载待插入的数据
2 cv.put("title","you are beautiful");//添加title
3 cv.put("weather","sun"); //添加weather
4 cv.put("context","xxxx"); //添加context
5 String publish = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
6                        .format(new Date());
7 cv.put("publish ",publish); //添加publish
8 db.insert("diary",null,cv);//执行插入操作2.使用execSQL方式来实现

String sql = "insert into user(username,password) values ('Jack Johnson','iLovePopMuisc');//插入操作的SQL语句
db.execSQL(sql);//执行SQL语句数据的删除

同样有2种方式可以实现

String whereClause = "username=?";//删除的条件
String[] whereArgs = {"Jack Johnson"};//删除的条件参数
db.delete("user",whereClause,whereArgs);//执行删除使用execSQL方式的实现

String sql = "delete from user where username='Jack Johnson'";//删除操作的SQL语句
db.execSQL(sql);//执行删除操作数据修改

同上,仍是2种方式

ContentValues cv = new ContentValues();//实例化ContentValues
cv.put("password","iHatePopMusic");//添加要更改的字段及内容
String whereClause = "username=?";//修改条件
String[] whereArgs = {"Jack Johnson"};//修改条件的参数
db.update("user",cv,whereClause,whereArgs);//执行修改使用execSQL方式的实现

String sql = "update user set password = 'iHatePopMusic' where username='Jack Johnson'";//修改的SQL语句
db.execSQL(sql);//执行修改数据查询

下面来说说查询操作。查询操作相对于上面的几种操作要复杂些,因为我们经常要面对着各种各样的查询条件,所以系统也考虑到这种复杂性,为我们提供了较为丰富的查询形式:

1 db.rawQuery(String sql, String[] selectionArgs); 
2 db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy); 
3 db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit); 
4 db.query(String distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);  上面几种都是常用的查询方法,第一种最为简单,将所有的SQL语句都组织到一个字符串中,使用占位符代替实际参数,selectionArgs就是占位符实际参数集;

各参数说明:

table:表名称
colums:表示要查询的列所有名称集
selection:表示WHERE之后的条件语句,可以使用占位符
selectionArgs:条件语句的参数数组
groupBy:指定分组的列名
having:指定分组条件,配合groupBy使用
orderBy:y指定排序的列名
limit:指定分页参数
distinct:指定“true”或“false”表示要不要过滤重复值
Cursor:返回值,相当于结果集ResultSet
最后,他们同时返回一个Cursor对象,代表数据集的游标,有点类似于JavaSE中的ResultSet。下面是Cursor对象的常用方法:

1 c.move(int offset); //以当前位置为参考,移动到指定行 
2 c.moveToFirst();    //移动到第一行 
3 c.moveToLast();    //移动到最后一行 
4 c.moveToPosition(int position); //移动到指定行 
5 c.moveToPrevious(); //移动到前一行 
6 c.moveToNext();    //移动到下一行 
7 c.isFirst();        //是否指向第一条 
8 c.isLast();    //是否指向最后一条 
9 c.isBeforeFirst();  //是否指向第一条之前 
10 c.isAfterLast();    //是否指向最后一条之后 
11 c.isNull(int columnIndex);  //指定列是否为空(列基数为0) 
12 c.isClosed();      //游标是否已关闭 
13 c.getCount();      //总数据项数 
14 c.getPosition();    //返回当前游标所指向的行数 
15 c.getColumnIndex(String columnName);//返回某列名对应的列索引值 
16 c.getString(int columnIndex);  //返回当前行指定列的值 实现代码

String[] params =  {12345,123456};Cursor cursor = db.query("user",columns,"ID=?",params,null,null,null);//查询并获得游标
if(cursor.moveToFirst()){//判断游标是否为空
    for(int i=0;i<cursor.getCount();i++){
        cursor.move(i);//移动到指定记录
        String username = cursor.getString(cursor.getColumnIndex("username");
        String password = cursor.getString(cursor.getColumnIndex("password"));
    }
}通过rawQuery实现的带参数查询

Cursor result=db.rawQuery("SELECT ID, name, inventory FROM mytable");
//Cursor c = db.rawQuery("s name, inventory FROM mytable where ID=?",new Stirng[]{"123456"});   
result.moveToFirst();
while (!result.isAfterLast()) {
    int id=result.getInt(0);
    String name=result.getString(1);
    int inventory=result.getInt(2);
    // do something useful with these
    result.moveToNext();
}
result.close();

在上面的代码示例中,已经用到了这几个常用方法中的一些,关于更多的信息,大家可以参考官方文档中的说明。

最后当我们完成了对数据库的操作后,记得调用SQLiteDatabase的close()方法释放数据库连接,否则容易出现SQLiteException。

上面就是SQLite的基本应用,但在实际开发中,为了能够更好的管理和维护数据库,我们会封装一个继承自SQLiteOpenHelper类的数据库操作类,然后以这个类为基础,再封装我们的业务逻辑方法。

这里直接使用案例讲解:下面是案例demo的界面



SQLiteOpenHelper类介绍

SQLiteOpenHelper是SQLiteDatabase的一个帮助类,用来管理数据库的创建和版本的更新。一般是建立一个类继承它,并实现它的onCreate和onUpgrade方法。

方法名 方法描述
SQLiteOpenHelper(Context context,String name,SQLiteDatabase.CursorFactory factory,int version) 构造方法,其中

context 程序上下文环境 即:XXXActivity.this;

name :数据库名字;

factory:游标工厂,默认为null,即为使用默认工厂;

version 数据库版本号

onCreate(SQLiteDatabase db) 创建数据库时调用
onUpgrade(SQLiteDatabase db,int oldVersion , int newVersion) 版本更新时调用
getReadableDatabase() 创建或打开一个只读数据库
getWritableDatabase() 创建或打开一个读写数据库

首先创建数据库类

1 import android.content.Context;
2 import android.database.sqlite.SQLiteDatabase;
3 import android.database.sqlite.SQLiteDatabase.CursorFactory;
4 import android.database.sqlite.SQLiteOpenHelper;
5
6 public class SqliteDBHelper extends SQLiteOpenHelper {
7
8    // 步骤1:设置常数参量
9    private static final String DATABASE_NAME = "diary_db";
10    private static final int VERSION = 1;
11    private static final String TABLE_NAME = "diary";
12
13    // 步骤2:重载构造方法
14    public SqliteDBHelper(Context context) {
15        super(context, DATABASE_NAME, null, VERSION);
16    }
17
18    /*
19      * 参数介绍:context 程序上下文环境 即:XXXActivity.this
20      * name 数据库名字
21      * factory 接收数据,一般情况为null
22      * version 数据库版本号
23      */
24    public SqliteDBHelper(Context context, String name, CursorFactory factory,
25            int version) {
26        super(context, name, factory, version);
27    }
28    //数据库第一次被创建时,onCreate()会被调用
29    @Override
30    public void onCreate(SQLiteDatabase db) {
31        // 步骤3:数据库表的创建
32        String strSQL = "create table "
33                + TABLE_NAME
34                + "(tid integer primary key autoincrement,title varchar(20),weather varchar(10),context text,publish date)";
35        //步骤4:使用参数db,创建对象
36        db.execSQL(strSQL);
37    }
38    //数据库版本变化时,会调用onUpgrade()
39    @Override
40    public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
41
42    }
43 }正如上面所述,数据库第一次创建时onCreate方法会被调用,我们可以执行创建表的语句,当系统发现版本变化之后,会调用onUpgrade方法,我们可以执行修改表结构等语句。

我们需要一个Dao,来封装我们所有的业务方法,代码如下:

1 import android.content.Context;
2 import android.database.Cursor;
3 import android.database.sqlite.SQLiteDatabase;
4
5 import com.chinasoft.dbhelper.SqliteDBHelper;
6
7 public class DiaryDao {
8
9    private SqliteDBHelper sqliteDBHelper;
10    private SQLiteDatabase db;
11
12    // 重写构造方法
13    public DiaryDao(Context context) {
14        this.sqliteDBHelper = new SqliteDBHelper(context);
15        db = sqliteDBHelper.getWritableDatabase();
16    }
17
18    // 读操作
19    public String execQuery(final String strSQL) {
20        try {
21            System.out.println("strSQL>" + strSQL);
22            // Cursor相当于JDBC中的ResultSet
23            Cursor cursor = db.rawQuery(strSQL, null);
24            // 始终让cursor指向数据库表的第1行记录
25            cursor.moveToFirst();
26            // 定义一个StringBuffer的对象,用于动态拼接字符串
27            StringBuffer sb = new StringBuffer();
28            // 循环游标,如果不是最后一项记录
29            while (!cursor.isAfterLast()) {
30                sb.append(cursor.getInt(0) + "/" + cursor.getString(1) + "/"
31                        + cursor.getString(2) + "/" + cursor.getString(3) + "/"
32                        + cursor.getString(4)+"#");
33                //cursor游标移动
34                cursor.moveToNext();
35            }
36            db.close();
37            return sb.deleteCharAt(sb.length()-1).toString();
38        } catch (RuntimeException e) {
39            e.printStackTrace();
40            return null;
41        }
42
43    }
44
45    // 写操作
46    public boolean execOther(final String strSQL) {
47        db.beginTransaction();  //开始事务
48        try {
49            System.out.println("strSQL" + strSQL);
50            db.execSQL(strSQL);
51            db.setTransactionSuccessful();  //设置事务成功完成
52            db.close();
53            return true;
54        } catch (RuntimeException e) {
55            e.printStackTrace();
56            return false;
57        }finally { 
58            db.endTransaction();    //结束事务 
59        } 
60
61    }
62 }我们在Dao构造方法中实例化sqliteDBHelper并获取一个SQLiteDatabase对象,作为整个应用的数据库实例;在增删改信息时,我们采用了事务处理,确保数据完整性;最后要注意释放数据库资源db.close(),这一个步骤在我们整个应用关闭时执行,这个环节容易被忘记,所以朋友们要注意。

我们获取数据库实例时使用了getWritableDatabase()方法,也许朋友们会有疑问,在getWritableDatabase()和getReadableDatabase()中,你为什么选择前者作为整个应用的数据库实例呢?在这里我想和大家着重分析一下这一点。

我们来看一下SQLiteOpenHelper中的getReadableDatabase()方法:

1 public synchronized SQLiteDatabase getReadableDatabase() { 
2    if (mDatabase != null && mDatabase.isOpen()) { 
3        // 如果发现mDatabase不为空并且已经打开则直接返回 
4        return mDatabase; 
5    } 

7    if (mIsInitializing) { 
8        // 如果正在初始化则抛出异常 
9        throw new IllegalStateException("getReadableDatabase called recursively"); 
10    } 
11 
12    // 开始实例化数据库mDatabase 
13 
14    try { 
15        // 注意这里是调用了getWritableDatabase()方法 
16        return getWritableDatabase(); 
17    } catch (SQLiteException e) { 
18        if (mName == null) 
19            throw e; // Can't open a temp database read-only! 
20        Log.e(TAG, "Couldn't open " + mName + " for writing (will try read-only):", e); 
21    } 
22 
23    // 如果无法以可读写模式打开数据库 则以只读方式打开 
24 
25    SQLiteDatabase db = null; 
26    try { 
27        mIsInitializing = true; 
28        String path = mContext.getDatabasePath(mName).getPath();// 获取数据库路径 
29        // 以只读方式打开数据库 
30        db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY); 
31        if (db.getVersion() != mNewVersion) { 
32            throw new SQLiteException("Can't upgrade read-only database from version " + db.getVersion() + " to " 
33                    + mNewVersion + ": " + path); 
34        } 
35 
36        onOpen(db); 
37        Log.w(TAG, "Opened " + mName + " in read-only mode"); 
38        mDatabase = db;// 为mDatabase指定新打开的数据库 
39        return mDatabase;// 返回打开的数据库 
40    } finally { 
41        mIsInitializing = false; 
42        if (db != null && db != mDatabase) 
43            db.close(); 
44    } 
45 }在getReadableDatabase()方法中,首先判断是否已存在数据库实例并且是打开状态,如果是,则直接返回该实例,否则试图获取一个可读写模式的数据库实例,如果遇到磁盘空间已满等情况获取失败的话,再以只读模式打开数据库,获取数据库实例并返回,然后为mDatabase赋值为最新打开的数据库实例。既然有可能调用到getWritableDatabase()方法,我们就要看一下了:

public synchronized SQLiteDatabase getWritableDatabase() { 
    if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) { 
        // 如果mDatabase不为空已打开并且不是只读模式 则返回该实例 
        return mDatabase; 
    } 
 
    if (mIsInitializing) { 
        throw new IllegalStateException("getWritableDatabase called recursively"); 
    } 
 
    // If we have a read-only database open, someone could be using it 
    // (though they shouldn't), which would cause a lock to be held on 
    // the file, and our attempts to open the database read-write would 
    // fail waiting for the file lock. To prevent that, we acquire the 
    // lock on the read-only database, which shuts out other users. 
 
    boolean success = false; 
    SQLiteDatabase db = null; 
    // 如果mDatabase不为空则加锁 阻止其他的操作 
    if (mDatabase != null) 
        mDatabase.lock(); 
    try { 
        mIsInitializing = true; 
        if (mName == null) { 
            db = SQLiteDatabase.create(null); 
        } else { 
            // 打开或创建数据库 
            db = mContext.openOrCreateDatabase(mName, 0, mFactory); 
        } 
        // 获取数据库版本(如果刚创建的数据库,版本为0) 
        int version = db.getVersion(); 
        // 比较版本(我们代码中的版本mNewVersion为1) 
        if (version != mNewVersion) { 
            db.beginTransaction();// 开始事务 
            try { 
                if (version == 0) { 
                    // 执行我们的onCreate方法 
                    onCreate(db); 
                } else { 
                    // 如果我们应用升级了mNewVersion为2,而原版本为1则执行onUpgrade方法 
                    onUpgrade(db, version, mNewVersion); 
                } 
                db.setVersion(mNewVersion);// 设置最新版本 
                db.setTransactionSuccessful();// 设置事务成功 
            } finally { 
                db.endTransaction();// 结束事务 
            } 
        } 
 
        onOpen(db); 
        success = true; 
        return db;// 返回可读写模式的数据库实例 
    } finally { 
        mIsInitializing = false; 
        if (success) { 
            // 打开成功 
            if (mDatabase != null) { 
                // 如果mDatabase有值则先关闭 
                try { 
                    mDatabase.close(); 
                } catch (Exception e) { 
                } 
                mDatabase.unlock();// 解锁 
            } 
            mDatabase = db;// 赋值给mDatabase 
        } else { 
            // 打开失败的情况:解锁、关闭 
            if (mDatabase != null) 
                mDatabase.unlock(); 
            if (db != null) 
                db.close(); 
        } 
    } 
}大家可以看到,几个关键步骤是,首先判断mDatabase如果不为空已打开并不是只读模式则直接返回,否则如果mDatabase不为空则加锁,然后开始打开或创建数据库,比较版本,根据版本号来调用相应的方法,为数据库设置新版本号,最后释放旧的不为空的mDatabase并解锁,把新打开的数据库实例赋予mDatabase,并返回最新实例。

看完上面的过程之后,大家或许就清楚了许多,如果不是在遇到磁盘空间已满等情况,getReadableDatabase()一般都会返回和getWritableDatabase()一样的数据库实例,所以我们在DBManager构造方法中使用getWritableDatabase()获取整个应用所使用的数据库实例是可行的。当然如果你真的担心这种情况会发生,那么你可以先用getWritableDatabase()获取数据实例,如果遇到异常,再试图用getReadableDatabase()获取实例,当然这个时候你获取的实例只能读不能写了

最后,让我们看一下如何使用这些数据操作方法来显示数据,界面核心逻辑代码:

public class SQLiteActivity extends Activity {

    public DiaryDao diaryDao;

    //因为getWritableDatabase内部调用了mContext.openOrCreateDatabase(mName, 0, mFactory); 
    //所以要确保context已初始化,我们可以把实例化Dao的步骤放在Activity的onCreate里
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        diaryDao = new DiaryDao(SQLiteActivity.this);
        initDatabase();
    }

    class ViewOcl implements View.OnClickListener {

        @Override
        public void onClick(View v) {

            String strSQL;
            boolean flag;
            String message;
            switch (v.getId()) {
            case R.id.btnAdd:
                String title = txtTitle.getText().toString().trim();
                String weather = txtWeather.getText().toString().trim();;
                String context = txtContext.getText().toString().trim();;
                String publish = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                        .format(new Date());
                // 动态组件SQL语句
                strSQL = "insert into diary values(null,'" + title + "','"
                        + weather + "','" + context + "','" + publish + "')";
                flag = diaryDao.execOther(strSQL);
                //返回信息
                message = flag?"添加成功":"添加失败";
                Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
                break;
            case R.id.btnDelete:
                strSQL = "delete from diary where tid = 1";
                flag = diaryDao.execOther(strSQL);
                //返回信息
                message = flag?"删除成功":"删除失败";
                Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
                break;
            case R.id.btnQuery:
                strSQL = "select * from diary order by publish desc";
                String data = diaryDao.execQuery(strSQL);
                Toast.makeText(getApplicationContext(), data, Toast.LENGTH_LONG).show();
                break;
            case R.id.btnUpdate:
                strSQL = "update diary set title = '测试标题1-1' where tid = 1";
                flag = diaryDao.execOther(strSQL);
                //返回信息
                message = flag?"更新成功":"更新失败";
                Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
                break;
            }
        }
    }

    private void initDatabase() {
        // 创建数据库对象
        SqliteDBHelper sqliteDBHelper = new SqliteDBHelper(SQLiteActivity.this);
        sqliteDBHelper.getWritableDatabase();
        System.out.println("数据库创建成功");
    }
}

Android sqlite3数据库管理工具

Android SDK的tools目录下提供了一个sqlite3.exe工具,这是一个简单的sqlite数据库管理工具。开发者可以方便的使用其对sqlite数据库进行命令行的操作。

程序运行生成的*.db文件一般位于"/data/data/项目名(包括所处包名)/databases/*.db",因此要对数据库文件进行操作需要先找到数据库文件:

1、进入shell 命令

adb shell2、找到数据库文件

#cd data/data
#ls                --列出所有项目
#cd project_name  --进入所需项目名
#cd databases   
#ls                --列出现寸的数据库文件3、进入数据库

#sqlite3 test_db  --进入所需数据库会出现类似如下字样:

SQLite version 3.6.22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite>至此,可对数据库进行sql操作。

4、sqlite常用命令

>.databases        --产看当前数据库
>.tables          --查看当前数据库中的表
>.help            --sqlite3帮助
>.schema            --各个表的生成语句

类别: 无分类 |  评论(0) |  浏览(53) |  收藏
2018年05月15日 15:24:48

Android变量保存的总结

Android系统app在后台运行时,由于内存不够或者清理内存后,会导致activity销毁或app进程被杀掉,此时变量数据的保存要注意:

以下几点时系统自动帮我们做的,我们不用关心:

1.用intent启动activity,intent中的数据;

2.Fragment使用setArguments设置参数,activity重启后可以直接使用getArguments获得原来设置的参数(Fragment参数传递推荐);

下面数据需要我们手动去保存和恢复:

1.如果进程被杀掉,app程序中使用的静态变量;

2.activity或Fragment被销毁时,其使用的临时变量;




Android系统由于内存问题回收app时,activity和Fragment都会调用onSaveInstanceState保存数据,我们只需复写即可,但一定要记得调用父类的此方法

类别: 无分类 |  评论(0) |  浏览(65) |  收藏
2018年05月10日 10:25:24

通达OA:未找到该群,是否未登录即时通讯

原因:
Office_IM服务被关闭,或因故退出关闭了

解决:
重新启动IM服务即可

类别: 无分类 |  评论(0) |  浏览(54) |  收藏
2018年05月08日 09:48:28

redis Out Of Memory allocating 56 bytes!

当出现以下错误时:

VirtualAlloc/COWAlloc fail! Out Of Memory allocating 42 bytes!


配置文件:
修改:maxmemory 1024000000

类别: 无分类 |  评论(0) |  浏览(67) |  收藏
2018年05月04日 10:55:42

mysql galera cluster集群的监控

一、集群复制状态检查

1、SHOW GLOBAL STATUS LIKE 'wsrep_%';

+------------------------------+-------------------------------------------------------------+
| Variable_name                | Value                                                      |
+------------------------------+-------------------------------------------------------------+
| wsrep_local_state_uuid      | 9f6a992a-7dd9-11e5-9f85-f760745ffb39                        |
| wsrep_protocol_version      | 7                                                          |
| wsrep_last_committed        | 53                                                          |
| wsrep_replicated            | 6                                                          |
| wsrep_replicated_bytes      | 1368                                                        |
| wsrep_repl_keys              | 9                                                          |
| wsrep_repl_keys_bytes        | 210                                                        |
| wsrep_repl_data_bytes        | 774                                                        |
| wsrep_repl_other_bytes      | 0                                                          |
| wsrep_received              | 37                                                          |
| wsrep_received_bytes        | 23347                                                      |
| wsrep_local_commits          | 0                                                          |
| wsrep_local_cert_failures    | 0                                                          |
| wsrep_local_replays          | 0                                                          |
| wsrep_local_send_queue      | 0                                                          |
| wsrep_local_send_queue_max  |2                                                         
| wsrep_local_send_queue_min  | 0                                                         
| wsrep_local_send_queue_avg  | 0.125000            |
| wsrep_local_recv_queue      | 0                                                          |
| wsrep_local_recv_queue_max  | 2                                      |
| wsrep_local_recv_queue_min  | 0                                              |
| wsrep_local_recv_queue_avg  | 0.027027                              |
| wsrep_local_cached_downto    | 14                                                          |
| wsrep_flow_control_paused_ns | 0                                                          |
| wsrep_flow_control_paused    | 0.000000                                                    |
| wsrep_flow_control_sent      | 0                                                          |
| wsrep_flow_control_recv      | 0                                                          |
| wsrep_cert_deps_distance    | 1.000000                                                    |
| wsrep_apply_oooe            | 0.100000                                                    |
| wsrep_apply_oool            | 0.000000                                                    |
| wsrep_apply_window          | 1.250000                                                    |
| wsrep_commit_oooe            | 0.000000                                                    |
| wsrep_commit_oool            | 0.000000                                                    |
| wsrep_commit_window          | 1.250000                                                    |
| wsrep_local_state            | 4                                                          |
| wsrep_local_state_comment    | Synced                                                      |
| wsrep_cert_index_size        | 10                                                          |
| wsrep_cert_bucket_count      | 22                                                          |
| wsrep_gcache_pool_size      | 27144                                                      |
| wsrep_causal_reads          | 0                                                          |
| wsrep_cert_interval          | 0.325000                                                    |
| wsrep_incoming_addresses    |  |
| wsrep_evs_delayed            |                                                            |
| wsrep_evs_evict_list        |                                                            |
| wsrep_evs_repl_latency      | 0/0/0/0/0                                                  |
| wsrep_evs_state              | OPERATIONAL                                                |
| wsrep_gcomm_uuid            | 5e28860a-829e-11e5-9c06-665d7fe4003d                        |
| wsrep_cluster_conf_id        | 3                                                          |
| wsrep_cluster_size          | 3                                                          |
| wsrep_cluster_state_uuid    | 9f6a992a-7dd9-11e5-9f85-f760745ffb39                        |
| wsrep_cluster_status        | Primary                                                    |
| wsrep_connected              | ON                                                          |
| wsrep_local_bf_aborts        | 0                                                          |
| wsrep_local_index            | 1                                                          |
| wsrep_provider_name          | Galera                                                      |
| wsrep_provider_vendor        | Codership Oy <info@codership.com>                          |
| wsrep_provider_version      | 3.12(rXXXX)                                                |
| wsrep_ready                  | ON                                                          |
+------------------------------+-------------------------------------------------------------+

wsrep_notify_cmd.sh——监控状态的变化。使用方法参见http://galeracluster.com/documentation-webpages/notificationcmd.html

2、wsrep_cluster_state_uuid显示了cluster的state UUID,由此可看出节点是否还是集群的一员

SHOW GLOBAL STATUS LIKE 'wsrep_cluster_state_uuid'

集群内每个节点的value都应该是一样的,否则说明该节点不在集群中了

+--------------------------+--------------------------------------+
| Variable_name                    | Value                                                  |
+--------------------------+--------------------------------------+
| wsrep_cluster_state_uuid | 9f6a992a-7dd9-11e5-9f85-f760745ffb39 |
+--------------------------+--------------------------------------+

3、wsrep_cluster_conf_id显示了整个集群的变化次数。所有节点都应相同,否则说明某个节点与集群断开了

4、wsrep_cluster_size显示了集群中节点的个数

5、wsrep_cluster_status显示集群里节点的主状态。标准返回primary。如返回non-Primary或其他值说明是多个节点改变导致的节点丢失或者脑裂。如果所有节点都返回不是Primary,则要重设quorum。具体参见http://galeracluster.com/documentation-webpages/quorumreset.html如果返回都正常,说明复制机制在每个节点都能正常工作,下一步该检查每个节点的状态确保他们都能收到write-set

show global status like 'wsrep_cluster_status';
+----------------------+---------+
| Variable_name        | Value  |
+----------------------+---------+
| wsrep_cluster_status | Primary |
+----------------------+---------+

二、检查节点状态

节点状态显示了集群中的节点接受和更新write-set状态,以及可能阻止复制的一些问题

1、wsrep_ready显示了节点是否可以接受queries。ON表示正常,如果是OFF几乎所有的query都会报错,报错信息提示“ERROR 1047 (08501) Unknown Command”

SHOW GLOBAL STATUS LIKE 'wsrep_ready';

+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wsrep_ready  | ON    |
+---------------+-------+

2、SHOW GLOBAL STATUS LIKE 'wsrep_connected’显示该节点是否与其他节点有网络连接。(实验得知,当把某节点的网卡down掉之后,该值仍为on。说明网络还在)丢失连接的问题可能在于配置wsrep_cluster_address或wsrep_cluster_name的错误

+-----------------+-------+
| Variable_name  | Value |
+-----------------+-------+
| wsrep_connected | ON    |
+-----------------+-------+

3、wsrep_local_state_comment 以人能读懂的方式显示节点的状态,正常的返回值是Joining, Waiting on SST, Joined, Synced or Donor,返回Initialized说明已不在正常工作状态

+---------------------------+--------+
| Variable_name            | Value  |
+---------------------------+--------+
| wsrep_local_state_comment | Synced |
+---------------------------+--------+

三、查看复制的健康状态

通过Flow Control的反馈机制来管理复制进程。当本地收到的write-set超过某一阀值时,该节点会启动flow control来暂停复制直到它赶上进度。监控本地收到的请求和flow control,有如下几个参数:

1、wsrep_local_recv_queue_avg——平均请求队列长度。当返回值大于0时,说明apply write-sets比收write-set慢,有等待。堆积太多可能导致启动flow control

+----------------------------+----------+
| Variable_name              | Value    |
+----------------------------+----------+
| wsrep_local_recv_queue_avg | 0.027027 |
+----------------------------+----------+

wsrep_local_recv_queue_max 和 wsrep_local_recv_queue_min可以看队列设置的最大最小值

2、wsrep_flow_control_paused 显示了自从上次查询之后,节点由于flow control而暂停的时间占整个查询间隔时间比。总体反映节点落后集群的状况。如果返回值为1,说明自上次查询之后,节点一直在暂停状态。如果发现某节点频繁落后集群,则应该调整wsrep_slave_threads或者把节点剔除

+---------------------------+----------+
| Variable_name            | Value    |
+---------------------------+----------+
| wsrep_flow_control_paused | 0.000000 |
+---------------------------+----------+

3、wsrep_cert_deps_distance显示了平行apply的最低和最高排序编号或者sql编号之间的平均距离值。这代表了节点潜在的并行程度,和线程相关

+--------------------------+----------+
| Variable_name            | Value    |
+--------------------------+----------+
| wsrep_cert_deps_distance | 1.000000 |
+--------------------------+----------+

四、检测网络慢的问题

通过检查发送队列来看传出的连接状况

1、wsrep_local_send_queue_avg显示自上次查询之后的平均发送队列长度。比如网络瓶颈和flow control都可能是原因

+----------------------------+----------+
| Variable_name              | Value    |
+----------------------------+----------+
| wsrep_local_send_queue_avg | 0.033333 |
+----------------------------+----------+

wsrep_local_send_queue_max 和 wsrep_local_send_queue_min可以看队列设置的最大值和最小值

五、日志监控

在my.cnf中做如下配置

# wsrep Log Options

wsrep_log_conflicts=ON  #会将冲突信息写入错误日志中,例如两个节点同时写同一行数据

wsrep_provider_options="cert.log_conflicts=ON"    #复制过程中的错误信息写在日志中

wsrep_debug=ON    #显示debug 信息在日志中,其中也包括鉴权信息,例如账号密码。因此在生产环境中不开启

六、附加的日志

当某节点在从节点上应用一个事件失败时,数据库服务器会创建一个特殊的binary log文件。文件名默认是GRA_*.log

类别: 无分类 |  评论(0) |  浏览(86) |  收藏
2018年05月04日 10:48:44

记一次MySQL中Waiting for table metadata lock的解决方法

没鸟用,仅供记录参考!

最近项目中的数据库查询经常挂起,应用程序启动后也报操作超时。测试人员就说数据库又挂了(貌似他们眼中的连接失败,查询无果都是挂了),通过 show processlist 一看,满屏都是 Waiting for table metadata lock 状态的连接。第一反应就是kill掉这些连接,奈何连接实在太多,实在kill不过来,于是重启服务,貌似重启果真能解决90%的问题,但如果不找到问题原因,问题也肯定会再次出现。

在网上查询得知MySQL在进行一些alter table等DDL操作时,如果该表上有未提交的事务则会出现 Waiting for table metadata lock ,而一旦出现metadata lock,该表上的后续操作都会被阻塞(详见 http://www.bubuko.com/infodetail-1151112.html)。所以这个问题需从两方面解决:

1. 查看未提交事务
从 information_schema.innodb_trx 表中查看当前未提交的事务

select trx_state, trx_started, trx_mysql_thread_id, trx_query from information_schema.innodb_trx\G1(\G作为结束符时,MySQL Client会把结果以列模式展示,对于列比较长的表,展示更直观)

字段意义:

trx_state: 事务状态,一般为RUNNING
trx_started: 事务执行的起始时间,若时间较长,则要分析该事务是否合理
trx_mysql_thread_id: MySQL的线程ID,用于kill
trx_query: 事务中的sql
一般只要kill掉这些线程,DDL操作就不会Waiting for table metadata lock。

2. 调整锁超时阈值
lock_wait_timeout 表示获取metadata lock的超时(单位为秒),允许的值范围为1到31536000(1年)。 默认值为31536000。详见 https://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html#sysvar_lock_wait_timeout 。默认值为一年!!!已哭瞎!将其调整为30分钟

set session lock_wait_timeout = 1800;
set global lock_wait_timeout = 1800;1好让出现该问题时快速故障(failfast)

类别: 无分类 |  评论(0) |  浏览(105) |  收藏
2018年05月04日 10:40:55

一次关于Waiting for table metadata lock的处理

一个简单的DDL操作(表数据很少,访问高)执行很久,导致Waiting for table metadata lock。

版本:mysql5.5.17

查看:Innodb_buffer_pool_pages_free = 0

解决:set global innodb_stats_on_metadata=0

查看丁奇老大博客:原文http://dinglin.iteye.com/blog/1575840


这个问题来自冷之同学测试时候碰到的一个“诡异现象”。


1、 测试现象     

测试的库有很多数据,但是重启之后,只对一个表的5w条记录作查询。查询条件客户端控制,确保查询范围。innodb_buffer_pool_size设置为35G。

现象1:查询性能会出现大幅度抖动;

现象2:介入追查后发现,Innodb_buffer_pool_pages_free = 0


        其中bp剩余量这个是最直观异常的,因为访问的5w行记录撑死也不可能把35G内存吃光的。在QA同学确认没有别人在使用这个库的情况下。


2、过程和原因

        其实几乎确定还是有别的查询在访问的。所以打开general_log。 发现除了QA同学压的语句外,这个Server上还有一些监控语句。

        其中一个语句如下

select constraint_schema,table_name,constraint_name,constraint_type from information_schema.table_constraints where table_schema not in ('information_schema', 'mysql', 'test'); 

        这个语句访问了表 information_schema.table_constraints.

跟踪发现这个语句触发了读盘操作。原因是需要访问引擎的info()接口,而InnoDB此时又“顺手”做了更新索引统计的操作dict_update_statistics。

更新索引统计的基本流程是随机读取部分demo行。所以这个操作实际上是访问了这个Server里面的所有表,因此不只是访问5w行。

而且由于别的表事先没有被访问,就会导致读盘操作,也包括BP的LRU更新。


3、哪些表会触发

        不只是上面提到的table_constraints,information_schema库下的一下几个表,访问时候都会触发这个“顺手”操作。

information_schema.TABLES

information_schema.STATISTICS

information_schema.PARTITIONS

information_schema.KEY_COLUMN_USAGE

information_schema.TABLE_CONSTRAINTS

information_schema.REFERENTIAL_CONSTRAINTS

        其实还有 show table status ,也会触发这个操作,只是只处理单表,所以影响没那么明显。


4、修改

头痛医头的方法是把这些监控去掉。但实际上像TABLES、TABLE_CONSTRAINTS这些表,都是静态数据,访问时不作索引统计也没关系的。

另外一个方法就是把innodb_stats_on_metadata设置成off,这样上述说到的这些表访问都不会触发索引统计。

        实际上这个动态统计的功能已经不推荐了,官方已经在6.0以后增加参数控制DML期间也不作动态统计了。因此这个参数配置成off更合理些(默认是on)

类别: 无分类 |  评论(0) |  浏览(94) |  收藏
2018年05月04日 10:37:35

waiting for table metadata lock 问题深入分析

https://blog.csdn.net/wlzjsj/article/details/50208957

      相信很多msyql dba都碰到锁的问题,在MySQL 5.5.3版本中引入了Metadata lock: DDL语句打破了事务的隔离级别。
那么会有同学问,为什么在Mysql 5.5.3之前就很少遇到这种锁呢?原因是
    5.5.3版本之前,MySQL事务对于表结构元数据(Metadata)的锁定是语句(statement)粒度的:即语句执行完成后,不管事务是否可以完成,其表结构就可以被其他会话更新掉!
    引入Metadata lock后,表结构元数据(Metadata)的锁定变成了事务(transaction)粒度的,即只有事务结束时才会释放Metadata lock。
怎么出现的?

程序或者脚本显式开启事务(start transaction),该事务内的query语句(包含select)会占用相关表的metadata lock(profile:Opening tables阶段)。导致后续的所有DDL操作语句全部被阻塞,原因就是获取不到metadata lock。(在mysql 5.6版本后有优化)官方手册参阅:http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html

我们下面以现网case来探讨这个问题的出现于解决:

case

业务执行一条简单的alter table 操作,增加一个字段,很普通的一条sql,而且表不大,数据量很少,执行却消耗几百秒没反应(现场忘记截图)


补充一个测试图

从图可以看出业务执行的语句遇到metadata lock了。

1、        分析mysql的实例的情况

1.1 mysql> show processlist;


除了有一个 Waiting for table 之外没有其它的操作进程,全部是sleep进程。这时你觉得奇怪吗?为什么没有其它的进程锁住这个表,会导致这个ddl语句一直卡住呢? 我们接着分析。

1.2 查看表是否太大 mysql> show table status like 'tbl_xx' \G


                          图1.2

看出表非常小,不存在由于数据量大导致更新慢的问题;

1.3 查看引擎状态 mysql> show engine innodb status \G


数据量太大,一屏幕都显示不完,不看了。

既然几个比较直接的方法都查不到原因,那只能更深入的查下了,我打算从数据字典中查下(information_schema,performance_schema):

1.4,查找当前等待事务:

mysql> select * from  performance_schema .events_waits_current;

Empty set (0.03 sec)

显示空。

查找information_schema中的事件表(EVENTS)、锁等待表(INNODB_LOCK_WAITS),innodb当前出现的锁(INNODB_LOCKS)均没看到异常(这里就不贴图了)。

1.5 查找事务

既然造成该锁的原因是事务没有提交导致的,那我们应该去查找当前是否有事务在运行(runing注:由于事务一直是runing状态,这也就是为什么我之前查找各种锁都找不到的原因)

mysql> select * from information_schema.innodb_trx;

(此图又被刷不见了)不过有重大发现:一个trx_mysql_thread_id: 275255348 是从trx_started: 2015-12-03 14:58:45 一直处于runing状态的。

既然我们找到了id了 那我们再回顾使用show processlist查找该ID就行了:


发现了吗,该ID一直是sleep状态。很难发现该进程打开了这个表(可以通过show open tables 查看当前打开的表)。


解决办法:询问了开发这个点的脚本,操作。确认后通过后台mysql 直接kill掉这个进程,业务的alter操作瞬间完成。

类别: 无分类 |  评论(0) |  浏览(92) |  收藏
2018年04月26日 12:49:55

last inactive check more than PT1.5S ago (PT2.82389S), skipping check

https://www.percona.com/blog/2016/06/02/galera-warning-last-inactive-check/


Galera warning “last inactive check”

Manjot Singh  | June 2, 2016 |  Posted In: Percona XtraDB Cluster, XtraDB Cluster
 






Galera warning "last inactive check"In this post, we’ll discuss the Galera warning “last inactive check” and what it means.

Problem

I’ve been working with Percona XtraDB Cluster quite a bit recently, and have been investigating various warnings. I came across this one today:

[Warning] WSREP: last inactive check more than PT1.5S ago (PT1.51811S), skipping check

This warning is related to the evs.inactive_check_period option. This option controls the poll period for the group communication response time. If a node is delayed, it is added to a delay list and it can lead to the cluster evicting the node.

Possible Cause

While some troubleshooting tips seem to associate the warning with VMWare snapshots, this isn’t the case here, as we see the warning on a physical machine.

I checked for backups or desynced nodes, and this also wasn’t the case. The warning was not accompanied by any errors or other information, so there was nothing critical happening.

In the troubleshooting link above, Galera developers said:


This can be seen on bare metal as well — with poorly configured mysqld, O/S, or simply being overloaded. All it means is that this thread could not get CPU time for 7.1 seconds. You can imagine that access to resources in virtual machines is even harder (especially I/O) than on bare metal, so you will see this in virtual machines more often.

This is not a Galera specific issue (it just reports being stuck, other mysqld threads are equally stuck) so there is no configuration options for that. You simply must make sure that your system and mysqld are properly configured, that there is enough RAM (buffer pool not over provisioned), that there is swap, that there are proper I/O drivers installed on guest and so on.

Basically, Galera runs in virtual machines as well as the virtual machines approximates bare metal.

It could also be an indication of unstable network or just higher average network latency than expected by the default configuration. In addition to checking network, do check I/O, swap and memory when you do see this warning.

Our graphs and counters otherwise look healthy. If this is the case, this is most likely nothing to worry about.

It is also a good idea to ensure your nodes are desynced before backup. Look for spikes in your workload. A further option to check for is that swappiness is set to 1 on modern kernels.

If all of this looks good, ensure the servers are all talking to the same NTP server, have the same time zone and the times and dates are in sync. While this warning could be a sign of an overloaded system, if everything else looks good this warning isn’t something to worry about.

Source

The warning comes from evs_proto.cpp in the Galera code:

if (last_inactive_check_ + inactive_check_period_*3 < now)
{
log_warn << "last inactive check more than " << inactive_check_period_*3
<< " ago (" << (now - last_inactive_check_)
<< "), skipping check";
last_inactive_check_ = now;
return;
}

Since the default for inactive_check_period is one second according to the Galera documentation, if it is now later than three seconds after the last check, it skips the rest of the above routine and adds the node to the delay list and does some other logic. The reason it does this is that it doesn’t want to rely on stale counters before making decisions. The message is really just letting you know that.

In Percona XtraDB Cluster, this setting defaults to 0.5s. This warning simply could be that your inactive_check_period is too low, and the delay is not high enough to add the node to the delay list. So you could consider increasing evs.inactive_check_period to resolve the warnings. (Apparently in Galera, it may also now be 0.5s but documentation is stale.)

Possible Solution

To find a sane value my colleague David Bennett came up with this command line, which gives you an idea of when your check warnings are happening:

$ cat mysqld.log | grep 'last inactive check more than' | perl -ne 'm/(PT(.*)S)/; print $1."n"' | sort -n | uniq -c
1 1.55228
1 1.5523
1 1.55257
1 1.55345
1 1.55363
1 1.5543
1 1.55436
1 1.55483
1 1.5552
1 1.55582

Therefore, in this case, it may be a good idea to set inactive_check_period at 1 or 1.5 to make the warnings go away.

Conclusion

Each node in the cluster keeps its own local copy of how it sees the topology of the entire cluster. check_inactive is a node event that is triggered every inactive_check_period seconds to help the node update its view of the whole cluster, and ensure it is accurate. Service messages can be broadcast to the cluster informing nodes of changes to the topology. For example, if a cluster node is going down it will broadcast a service message telling each node in the cluster to remove it. The action is queued but the actual view of the cluster is updated with check_inactive. This is why it adds nodes to its local copy of inactive, suspect and delayed nodes.

If a node thinks it might be looking at stale data, it doesn’t make these decisions and waits until the next time for a fresh queue. Unfortunately, if inactive_check_period is too low, it will keep giving you warnings.

类别: 无分类 |  评论(0) |  浏览(77) |  收藏
2018年04月20日 09:59:23

android6.0系统缺少com.android.internal.policy.PolicyManager导致无法获取LayoutInflater实例问题

问题出现原因:

插件技术动态加载View需要实例化一个LayoutInflater,但6.0以后com.android.internal.policy.PolicyManager被去除,导致插件view无法被创建,为了能让我的app能够在6.0系统上运行,我必须解决掉这个bug

解决办法:

搜素源码找到这个类:
https://android.googlesource.com/platform/frameworks/base/+/android-6.0.1_r25/core/java/com/android/internal/policy/PhoneLayoutInflater.java
可以通过实例化它取得LayoutInflater,具体代码如下:
博客出处: (http://georgeyang.cn/)

policyClass = Class.forName("com.android.internal.policy.PhoneLayoutInflater");
Constructor<?> localConstructor = policyClass.getConstructor(new Class[]{Context.class});
mLayoutInflater = (LayoutInflater) localConstructor.newInstance(new Object[]{context});


如果你的项目需要经过com.android.internal.policy.PolicyManager获取windows

Class windowClass = Class.forName("com.android.internal.policy.PhoneWindow");
Constructor<?> localConstructor = windowClass.getConstructor(new Class[]{Context.class});
Window windows = (Window) localConstructor.newInstance(new Object[]{getApplicationContext()});//实例化Window,如果传的context不是Application的Context,就会奔溃
Field field = windowClass.getDeclaredField("mLayoutInflater");
field.setAccessible(true);
mLayoutInflater = (LayoutInflater) field.get(windows);//取得Application的LayoutInflater,而不是插件的LayoutInflater

//往windows设置插件的LayoutInflater
policyClass = ReflectUtil.getClass("com.android.internal.policy.PhoneLayoutInflater");
Constructor<?> policyLocalConstructor = policyClass.getConstructor(new Class[]{Context.class});
mLayoutInflater = (LayoutInflater) policyLocalConstructor.newInstance(new Object[]{this});
field.set(windows,mLayoutInflater);

参考源码:
https://android.googlesource.com/platform/frameworks/base/+/android-6.0.1_r25/core/java/com/android/internal/policy/PhoneWindow.java

类别: 无分类 |  评论(0) |  浏览(78) |  收藏
2018年04月11日 08:40:08

Android Webview中解决H5的音视频不能自动播放的问题

Android Webview中解决H5的音视频不能自动播放的问题

这是网上一个常见方案:

  在开发webview的时候,当加载有声音的网页的时候,声音不会自动播放,但在QQ或者系统浏览器可以自动播放,查找资料还需要最后通过在webview中调用js方法。这个方法需要在webview的setWebViewClient方法之后在onPageFinished回调中执行调用。
webView.setWebViewClient(new WebViewClient() {
                                @Override
                                public void onPageFinished(WebView view, String url) {
                                    super.onPageFinished(view, url);
                                    spWebView.loadUrl("javascript:(function() { " +
                                            "var videos = document.getElementsByTagName('audio');" +
                                            " for(var i=0;i<videos.length;i++){videos.play();}})()");
                                }

                                @Override
                                public void onPageStarted(WebView view, String url, Bitmap favicon) {

                                    super.onPageStarted(view, url, favicon);
                                }
                            });

更专业的作法:

            For Android < 4.2.2 it seems that the last DOM event you get is 'loadeddata'. You likely won't get "canplaythrough". To autoplay, you then use javascript var myvideo = document.getElementsByTagName('video')[0]; myvideo.play();

            For Android 4.2.2+ all you need in your native code is WebView.getSettings().setMediaPlaybackRequiresUserGesture(false);

类别: 无分类 |  评论(0) |  浏览(279) |  收藏
2018年04月03日 11:46:04

resource android:attr/preserveIconSpacing is private

我是修改报错的文件:C:\Users\Administrator\.gradle\caches\transforms-1\files-1.1\appcompat-v7-19.1.0.aar\8c83f962a957796f5be5cd1887b0c741\res\values\values.xml
找到
<attr name="android:preserveIconSpacing" />
改为
<attr name="preserveIconSpacing" />

就不再报错了,暂未发现副作用。根据下面的英文,应该还有需要处理的地方。


问题:

I have created a completely new project in Android Studio 3.0. Gradle build works fine in this newly instantiated project, until I insert the following lines in my module's build.gradle

dependencies {
    ...
    compile 'com.github.gabrielemariotti.cards:cardslib-core:2.1.0'
    compile 'com.github.gabrielemariotti.cards:cardslib-cards:2.1.0'
    compile 'com.github.gabrielemariotti.cards:cardslib-recyclerview:2.1.0'
}
Here is the error I get in the Build log

/home/sparker0i/.gradle/caches/transforms-1/files-1.1/appcompat-v7-26.0.1.aar/e06e09188fb79d4d895b39247477d1c1/res/values/values.xml
Error:(246, 5) resource android:attr/foregroundInsidePadding is private
When I double click on it, I get a values.xml file (merged one), where the pointer is at

<dimen name="abc_action_bar_content_inset_material">16dp</dimen>
My minimum SDK version is 16, target SDK is 26. I am using Android Studio 3.0 Beta 2, build tools version is 26.0.1. Gradle plugin 3.0.0-beta2.

I bet this is because of a slightly outdated Cardslib library. Is there no way to fix this? (Removing those lines from dependencies works fine)


一个回复:

Try disabling the AAPT2 by adding android.enableAapt2=false to your gradle.properties file.

Builds may fail while AAPT2 is enabled. Additionally, AAPT2 is currently not compatible with Robelectric. If your build fails due to an AAPT2 resource processing issue or you want to use Roboelectric, you can disable AAPT2 by setting android.enableAapt2=false in your gradle.properties file and restarting the Gradle daemon by running ./gradlew --stop from the command line.

Reference : https://developer.android.com/studio/build/gradle-plugin-3-0-0.html

I was using Android studio 3.0 beta 5 In which I disabled the AAPT2 and it resolved my error.

UPDATE: 28 March 2018

With Android Studio 3.1.1 this might not work. One of your library might be using android's private resource. You need to find the error causing library and replace android:attr/foregroundInsidePadding with foregroundInsidePadding and import it to your project.

1.Clone the library repo in your local.
2.Open repository in Android Studio find xml having <attr name="android:foregroundInsidePadding" /> and replace it with
<attr name="foregroundInsidePadding" /> and Build.
3.Open your project and import that repository as dependency into your project.
4.Remove library compile statements from app level build.gradle.
5.Now you might be able to use AAPT2 so try changing android.enableAapt2=false to true in gradle.properties if present.

类别: 无分类 |  评论(0) |  浏览(1261) |  收藏
2018年04月02日 22:57:52

登录到 IMM Web GUI 界面 IBM LENOVO 使用“集成管理模块”

【登录到 IMM Web 界面】
http://systemx.lenovofiles.com/help/topic/com.lenovo.sysx.3837.doc/nn1em_t_ugch3logontowebinterface.html

关于此任务

要登录到 IMM2 Web 界面,请完成以下步骤:


过程
1. 在连接到服务器的系统上,打开 Web 浏览器。在地址或 URL 字段中,输入要连接的 IMM 的 IP 地址或主机名。
注: 如果这是您在安装后第一次登录 IMM,那么 IMM 将缺省使用 DHCP。如果 DHCP 主机不可用,那么 IMM 会将静态 IP 地址指定为 192.168.70.125。IMM 网络访问标记提供 IMM 的缺省主机名,并且不需要您启动服务器。

2. 在登录页面中,输入用户名和密码。如果这是您第一次使用 IMM,那么可以从系统管理员处获取用户名和密码。所有登录尝试都会记录在系统事件日志中。
注: 最初设置的 IMM 用户名为 USERID,密码为 PASSW0RD(是数字“零”,而不是字母“O”)。您具有读/写访问权。 当您第一次登录时,必须更改缺省密码。

3. 单击 Log in 以启动会话。System Status and Health 页面使您可以快速查看系统状态。



下一步做什么

注: 如果您在 IMM GUI 中时引导到操作系统,并在 System Status → System State 下显示消息“Booting OS or in unsupported OS”,请禁用 Windows 2008 防火墙或者在 Windows 2008 控制台中输入以下命令。这可能还影响蓝屏捕获功能。
netsh firewall set icmpsetting type=8 mode=ENABLE
缺省情况下,icmp 包被 Windows 防火墙阻止。然后,在您如上所示在 Web 界面和 CLI 界面中更改设置之后,IMM GUI 将变为“OS booted”状态。


【使用“集成管理模块”】
http://systemx.lenovofiles.com/help/topic/com.lenovo.sysx.3837.doc/nn1em_r_ugch3usingimm.html

本主题提供了集成管理模块 II (IMM2) 系统管理功能部件的概述。


集成管理模块 II (IMM2) 是先前由 BMC 控制器硬件所提供功能的第二代版本。它将服务处理器功能、视频控制器和远程感知功能整合到一块芯片中。

有关 IMM2 的更多信息,请参阅位于以下地址的 Integrated Management Module II User's Guide:http://www.ibm.com/support/entry/portal/docdisplay?lndocid=MIGR-5086346。


IMM 支持以下基本的系统管理功能:

Active Energy Manager。
警报(频带内和频带外报警、PET 陷阱 - IPMI 样式、SNMP 和电子邮件)。
自动引导故障恢复(ABR)。
在多微处理器配置中,当一个微处理器发出内部错误信号时,自动禁用发生故障的微处理器并重新启动。当某个微处理器发生故障时,服务器将禁用该发生故障的微处理器,并采用另一个微处理器重新启动。
注: 在四微处理器配置中,当一个微处理器发生故障时,将禁用两个微处理器。

服务器自动重启 (ASR),如果 POST 未完成或者操作系统挂起并且操作系统看守程序计时器超时,就会执行此功能。如果启用了 ASR 功能,那么可以配置 IMM 来监控操作系统看守程序计时器并在出现超时后重新引导系统。否则,IMM 允许管理员通过按服务器后部的不可屏蔽中断 (NMI) 按钮来生成 NMI,以进行操作系统内存转储。IPMI 支持 ASR。
远程感知支持(远程视频、远程键盘/鼠标和远程存储器)。
引导顺序处理。
命令行界面。
配置保存和恢复。
DIMM 错误帮助。“统一可扩展固件接口”(UEFI)会禁用在 POST 期间检测到的发生故障的 DIMM,IMM 将点亮相关的系统错误指示灯和表明 DIMM 发生故障的错误指示灯。
环境监控器,用于监控风扇速度、温度、电压、风扇故障、电源故障和电源底板故障。
首次故障数据捕获 (FFDC) 支持。
“智能平台管理接口”(IPMI)规范 V2.0 和“智能平台管理总线”(IPMB)支持。
无效系统配置 (CONFIG) 指示灯支持。
光通路诊断指示灯,用于报告风扇、电源、微处理器、硬盘驱动器发生的错误以及系统错误。
本地固件代码闪存更新
不可屏蔽中断 (NMI) 检测、生成和报告。
操作系统故障蓝屏捕获。
PCI 配置数据。
PECI 3 支持。
电源/复位控制(开机、硬关机和软关机、硬复位和软复位以及电源控制计划安排)。
查询电源输入功率。
基于 ROM 的 IMM 固件闪存更新。
Serial over LAN(SOL)。
使用 telnet 或 ssh 的串口重定向。
SMI 处理
系统事件日志 (SEL) - 用户可读的事件日志。


IMM 还通过 OSA SMBridge 管理实用程序提供了以下远程服务器管理能力:

命令行界面(IPMI Shell)
命令行界面使您可通过 IPMI 2.0 协议直接访问服务器管理功能。您可以使用命令行界面发出命令以控制服务器电源、查看系统信息和识别服务器。您还可以将一条或多条命令作为文本文件保存,并将该文件作为脚本运行。

Serial over LAN 
建立“Serial over LAN”(SOL)连接,以从远程位置管理服务器。您可以远程查看和更改 UEFI 设置、重新启动服务器、识别服务器以及执行其他管理功能。任何标准的 Telnet 客户机应用程序都可访问 SOL 连接。

类别: 无分类 |  评论(0) |  浏览(96) |  收藏
2018年04月02日 22:53:21

POST hang at 'Loading Value-add drivers' after UEFI updated

POST hang at 'Loading Value-add drivers' after UEFI updated from version 1.0/1.1 TO 2.0 - Lenovo x86 servers 

Symptom:
PowerOnSelfTest(POST)hangsat"Loadingvalue-adddrivers"afterUEFIcodeisupdatedfromversion1.0/1.1to2.0.
AffectedConfiguration:

ThesystemmaybeanyofthefollowingLenovoservers:
LenovoFlexSystemx240M5ComputeNode,type2591,anymodel
LenovoFlexSystemx240M5ComputeNode,type9532,anymodel
LenovoNeXtScalenx360M5,type5465,anymodel
LenovoNeXtScalenx360M5,type5467,anymodel
LenovoSystemx3550M5,type5463,anymodel
LenovoSystemx3650M5,type5462,anymodel

ThefollowingsystemBIOSorUEFIlevel(s)areaffected:
UEFIversionspriorto1.2
Thistipisnotoptionspecific.

Thistipisnotsoftwarespecific.

Solution:
Thisisapermanentrestriction,therewillbenosolution.

Workaround:

Ifthesystemhasnotencountertheissueyet,followbelowproceduretoupdateUEFI2.00.
1.UpgradeUEFItoversion1.2first.
2.Poweronthesystemandensurethesystemcanbootsuccessfully.
3.ThenupgradeUEFItoversion2.0.

IfthesystemalreadyencounteredPOSThangproblem,pleasefollowbelowproceduretorecoverythesystem.Donotreplacesystemboardforthisissue.
1.Poweroffthesystem.
2.DowngradeUEFItoversion1.2viaIntegratedManagementModule(IMM)webGraphicalUserInterface(GUI).
3.Poweronthesystemandensurethesystemcanbootsuccessfully.
4.ThenupgradeUEFItoversion2.0.

Transitionversioninformationofaffectedsystems:
Version1.20-LenovoSystemx3550M5,Type5463,anymodel
Version1.20-LenovoSystemx3650M5,Type5462,anymodel
Version1.20-LenovoSystemx240M5,Type2591,anymodel
Version1.20-LenovoSystemx240M5,Type9532,anymodel
Version1.31-LenovoSystemnx360M5,Type5465,anymodel
Version1.31-LenovoSystemnx360M5,Type5467,anymodel



在UEFI從1.0/1.1到2.0版更新後,POST掛起於“加載增值驅動程序”-Lenovox86服務器

本文內容是採用電腦自動翻譯方式完成

症狀:
在UEFI代碼從1.0/1.1更新到2.0之後,開機自檢(POST)掛起於“加載增值驅動程序”。
受影響的配置:

該系統可能是以下任何Lenovo服務器:
LenovoFlex系統x240M5計算節點,類型2591,任何型號
LenovoFlex系統x240M5計算節點,類型9532,任何型號
LenovoNeXtScalenx360M5,5465型,任何型號
LenovoNeXtScalenx360M5,型號5467,任何型號
Lenovo系統x3550M5,型號5463,任何型號
Lenovo系統x3650M5,型號5462,任何型號

以下系統BIOS或UEFI級別受到影響:
UEFI版本之前1.2
這個提示不是特定的選項。

這個提示不是軟件特定的。

解:
這是一個永久限制,不會有解決辦法。

解決辦法:

如果系統尚未遇到問題,請按照以下步驟更新UEFI2.00。
1.將UEFI升級到版本1.2first12123300nbsp;
2.打開系統電源,確保系統啟動成功.122323300nbsp;
3.然後將UEFI升級到2.0版。

如果系統已經遇到POST掛起問題,請按照以下步驟恢復系統.1223300nbsp;不要為此問題替換系統板。
1.關閉系統電源。
2.通過集成管理模塊(IMM)Web圖形用戶界面(GUI)將UEFI降級到版本1.2。
3.打開系統電源並確保系統啟動成功。
4.然後將UEFI升級到2.0版。

受影響系統的過渡版本信息:
版本1.20-LenovoSystemx3550M5,5463型,任何型號
版本1.20-Lenovo系統x3650M5,類型5462,任何型號
版本1.20-Lenovo系統x240M5,類型2591,任何型號
版本1.20-Lenovo系統x240M5,類型9532,任何型號
版本1.31-Lenovo系統nx360M5,類型5465,任何型號
版本1.31-LenovoSystemnx360M5,型號5467,任何型號

类别: 无分类 |  评论(0) |  浏览(345) |  收藏
« 1 2345» Pages: ( 1/19 total )