月份:2015年5月

2015年互联网女皇趋势报告完整版

【197页PPT:“互联网女皇报告,解密2015互联网的新商机】

这是享有“互联网女皇”美誉的玛丽·米克尔(Mary Meeker)每年一期的互联网趋势报告中文版。这份报告包含了对互联网发展趋势的完整剖析,覆盖移动设备到互联网使用的方方面面,深度解读的各细分领域的行业趋势,推荐收藏。

下载:http://7xj7on.com2.z0.glb.qiniucdn.com/Internet_Trends_2015.pdf

2015.05.28 数据库挂了

上午携程网的数据库挂了,网站到现在还没恢复服务,携程的产品经理也很有想法啊,改了一下公告,把用户引导到刚收购的艺龙,结果一会儿,艺龙也挂了,直接页面都打不开,可能是流量过大,服务器顶不住了。

有意思的是,我们公司的数据库下午也出问题了,技术人员在群里也不说个一二,不知道到底是怎么回事,到现在还是时好时坏,不知道是被攻击了还是怎么回事。

下午A股大跌300多点,我感觉这几天会回调,但是没想到这么快,而且居然是暴跌。手贱的我上午还买了点基金,还好不多。

惊心动魄的一天,其实也还是普通的一天。

CentOS实现mysql数据库的自动备份

1、写备份脚本 mysqlbak.sh:

  1. #!/bin/bash
  2. id=“root” #用户名
  3. pwd=“xxxxxx” #密码
  4. dbs=“1111 222 222 444” #数据库名字的列表,多个数据库用空格分开。
  5. backuppath=“/home/mysqlbackup” #保存备份的位置
  6. day=15   #保留最近几天的备份
  7. [ ! -d $backpath ] &&mkdir -p $backuppath  #判断备份目录是否存在,不存时新建目录。
  8. cd $backuppath   #转到备份目录,这句话可以省略。可以直接将路径到命令的也行。
  9. backupname=mysql_$(date +%Y-%m-%d)  #生成备份文件的名字的前缀,不带后缀。
  10. for db in $dbs;   #dbs是一个数据名字的集合。遍历所有的数据。
  11. do
  12.    mysqldump -u$id -p$pwd -S /var/lib/mysql/mysql.sock $db >$backupname_$db.sql  #备份单个数据为.sql文件。放到当前位置
  13.    if [ “$?” == “0” ]  #$? 得到上一个shell命令的执行的返回值。0表示执行成功。其他表示错误。并将将结果写入到日志中。
  14.    then
  15.        echo $(date +%Y-%m-%d)” $db  mysqldump sucess”>>mysql.log
  16.    else
  17.       echo $(date +%Y-%m-%d)”  $db mysql dump failed”>>mysql.log
  18.       exit 0
  19.    fi
  20. done
  21. tar -czf $backupname.tar.gz *.sql #压缩所有sql文件
  22. if [ “$?” == “0” ]
  23. then
  24.    echo $(date +%Y-%m-%d)” tar sucess”>>mysql.log
  25. else
  26.    echo $(date +%Y-%m-%d)” tar failed”>>mysql.log
  27.    exit 0
  28. fi
  29. rm -f *.sql  #删除所有的sql文件
  30. delname=mysql_$(date -d “$day day ago” +%Y-%m-%d).tar.gz  #得到要删除的太旧的备份的名字。
  31. rm -f $delname  #删除文件。

2、在 /etc/crontab中添加一行,就可以在指定时间,自动备份了

01 00 * * * /usr/sbin/mysqlbak.sh   #指定每天凌晨1点执行脚本

 

甲沟炎again,好了伤疤忘了疼

08年在深圳就得过一次甲沟炎,就是因为把指甲盖旁边的倒刺导致感染了。那次在一个药店,一个小年轻大夫给我上了点药包扎了一下,没几天就好了。这次好像严重,都化脓了。上午去朝阳医院切开放脓,先打麻药后切,疼啊。麻药过后,疼了一上午。以后再不敢拔倒刺了。

不过想想这和媳妇生孩子的疼比起来就小巫见大巫了吧。。。。

善待身边的陌生人

上周六去早市修自行车,修自行车的师傅不在。我问旁边的理发师傅,他说修自行车的师傅病了,好几天没来了。当时觉得挺失落的,一是要跑到另一个比较远的地方去修自行车,一是修自行车的师傅得什么病了?希望是感冒之类的小病吧。

其实我没有在那里修过自行车,因为自行车没出过什么问题。我只是知道那个师傅的修车摊一直在那里,去早市买菜的时候不经意的会看到他在那里修自行车。这几天碰巧自行车坏了,第一时间就想到那里能修,但是碰巧师傅没出摊。

现在电动车兴起,骑自行车的人远不如以前多了,修自行车的人也就相应的少了很多。偶尔有几个修车摊,修车师傅也基本上是上了岁数的大爷。他们基本上没有固定的门面,在十字路口的一角,找一棵树下,把工具摆开,拿一搪瓷盆装满一盆黑呼呼的水,就开工了。有的修车师傅在树枝上挂一个废弃的自行车轮胎,当做一个标志,告诉路人这里可以修自行车。这种修车师傅,在我看来,他们大部分人并不以赚钱为目的,有的人就是在老了的时候找点事做,继续体现自己的价值。时间长了,就有了一种使命感,他不出摊,有的顾客就会扑空。所以他们已经养成了一种习惯,除了恶劣的天气外,他们会准时出摊,哪怕没几个顾客,也可以和其他的老友聊聊天,也不至于孤独。

我们的自行车不会经常出问题,所以我们对这些师傅没有太多的印象,我们一年当中也不会和他们接触多少次,更不会在任何时候想起他们,当然,除了自行车坏了的时候,我们会发现我们还是很需要他们的。这个时候我就想到,这些人的坚持,其实就是为了某个不相识的顾客,在某个普通的日子,来找他们搞定出了问题的自行车,挣不了几个小钱,但是他们很有成就感。

想想我们身边其实很多这样的人群,其实他们就像空气,大部分时间,我们看不到他们,但是我们确实是需要他们。其实每天匆匆擦肩的陌生人,就有可能是这样的一些人,我们平时没有交集,但是在某个场景,我们可能就是对方的空气。以前就看过类似的一篇文章讲到这样的观点,现在很有感触。所以,善待身边的陌生人,其实就是善待了自己。

精益创业,不只是说说而已

《精益创业》这本书一直没有读完,但是其中心思想已经被很多人总结过了,知乎上一个提问的回复就很精彩:怎么理解「精益创业」创业模式?

今天想到去年和同学合伙做微信营销平台的事情,总结一下失败的原因:

事情起因:

某天一起喝酒吃饭,我提议当前微信营销平台很火,但是做的人也很多,我们能不能做呢?同学说客户很多,他之前就是做餐饮行业广告的,手上有很多客户。我一想市场很大,这样我们能成几单就算赚了,3个人一人投个几千块钱就可以搞起了,试一把吧。

接下来才是犯错的时候,搭建平台,有两种方式:1、做代理,市面上有微盟之类的平台,可以加盟;2、买源码,小猪pigcms做得比较大,就是比较贵,得1-2万一套系统;3、用盗版,淘宝上几块钱的都有,功能不太全,售后无法保障。这时候我信心满满,考虑到以后要给客户提供可靠稳定的系统,直接上正版,直接买了一套小猪pigcms的系统。然后呢,然后就没有然后了,到现在为止一个客户没谈成,当然,跟我们都上班,没有专门去做这件事也有关。

啰嗦了这么多,要说的是,其实在搭建平台的时候,就可以用到精益创业的思维了。方法就是:直接淘宝花1块钱买套系统,把网站搭建好,然后开始跑客户,给客户演示平台,盗版的就足够了。如果客户谈成了,交了定金,哪怕这时候再买正版系统,都不至于亏钱。更悲催的是,我本身就有现成的一套还算可靠的微信营销系统在线上了。

拿别人的话来总结就是:在产品研发、创意执行之前,用最低的成本最快的方法进行市场测试,或在小范围内先进行试验

精益创业的思维,不只是说说而已,要用到实际生活中、工作中才行!

Python学习:Day 2 – 编写数据库模块

网上有很多现成的访问MySql数据库的Python模块,但是作者本章准备自己写一个简单易用的db模块。从第二天就开始有难度了…好在作者在GitHub上提供了教程所有的源码,时不时可以偷看几眼。第二天教程对应的源码是:https://github.com/michaelliao/awesome-python-webapp/tree/day-02,修改对应的day即可访问对应的源码。

db.py文件:

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. __author__ = ‘Michael Liao’
  4. ”’
  5. Database operation module.
  6. ”’
  7. import time, uuid, functools, threadinglogging
  8. # Dict object:
  9. class Dict(dict):
  10.     ”’
  11.     Simple dict but support access as x.y style.
  12.     >>> d1 = Dict()
  13.     >>> d1[‘x’] = 100
  14.     >>> d1.x
  15.     100
  16.     >>> d1.y = 200
  17.     >>> d1[‘y’]
  18.     200
  19.     >>> d2 = Dict(a=1, b=2, c=’3′)
  20.     >>> d2.c
  21.     ‘3’
  22.     >>> d2[’empty’]
  23.     Traceback (most recent call last):
  24.         …
  25.     KeyError: ’empty’
  26.     >>> d2.empty
  27.     Traceback (most recent call last):
  28.         …
  29.     AttributeError: ‘Dict’ object has no attribute ’empty’
  30.     >>> d3 = Dict((‘a’, ‘b’, ‘c’), (1, 2, 3))
  31.     >>> d3.a
  32.     1
  33.     >>> d3.b
  34.     2
  35.     >>> d3.c
  36.     3
  37.     ”’
  38.     def __init__(self, names=(), values=(), **kw):
  39.         super(Dict, self).__init__(**kw)
  40.         for k, v in zip(names, values):
  41.             self[k] = v
  42.     def __getattr__(self, key):
  43.         try:
  44.             return self[key]
  45.         except KeyError:
  46.             raise AttributeError(r”‘Dict’ object has no attribute ‘%s'” % key)
  47.     def __setattr__(self, key, value):
  48.         self[key] = value
  49. def next_id(t=None):
  50.     ”’
  51.     Return next id as 50-char string.
  52.     Args:
  53.         t: unix timestamp, default to None and using time.time().
  54.     ”’
  55.     if t is None:
  56.         t = time.time()
  57.     return ‘%015d%s000’ % (int(t * 1000), uuid.uuid4().hex)
  58. def _profiling(start, sql=”):
  59.     t = time.time() – start
  60.     if t > 0.1:
  61.         logging.warning(‘[PROFILING] [DB] %s: %s’ % (t, sql))
  62.     else:
  63.         logging.info(‘[PROFILING] [DB] %s: %s’ % (t, sql))
  64. class DBError(Exception):
  65.     pass
  66. class MultiColumnsError(DBError):
  67.     pass
  68. class _LasyConnection(object):
  69.     def __init__(self):
  70.         self.connection = None
  71.     def cursor(self):
  72.         if self.connection is None:
  73.             connection = engine.connect()
  74.             logging.info(‘open connection <%s>…’ % hex(id(connection)))
  75.             self.connection = connection
  76.         return self.connection.cursor()
  77.     def commit(self):
  78.         self.connection.commit()
  79.     def rollback(self):
  80.         self.connection.rollback()
  81.     def cleanup(self):
  82.         if self.connection:
  83.             connection = self.connection
  84.             self.connection = None
  85.             logging.info(‘close connection <%s>…’ % hex(id(connection)))
  86.             connection.close()
  87. class _DbCtx(threading.local):
  88.     ”’
  89.     Thread local object that holds connection info.
  90.     ”’
  91.     def __init__(self):
  92.         self.connection = None
  93.         self.transactions = 0
  94.     def is_init(self):
  95.         return not self.connection is None
  96.     def init(self):
  97.         logging.info(‘open lazy connection…’)
  98.         self.connection = _LasyConnection()
  99.         self.transactions = 0
  100.     def cleanup(self):
  101.         self.connection.cleanup()
  102.         self.connection = None
  103.     def cursor(self):
  104.         ”’
  105.         Return cursor
  106.         ”’
  107.         return self.connection.cursor()
  108. # thread-local db context:
  109. _db_ctx = _DbCtx()
  110. # global engine object:
  111. #数据库引擎对象:
  112. engine = None
  113. class _Engine(object):
  114.     def __init__(self, connect):
  115.         self._connect = connect
  116.     def connect(self):
  117.         return self._connect()
  118. def create_engine(user, password, database, host=’127.0.0.1′, port=3306, **kw):
  119.     import mysql.connector
  120.     global engine
  121.     if engine is not None:
  122.         raise DBError(‘Engine is already initialized.’)
  123.     params = dict(user=user, password=password, database=database, host=host, port=port)
  124.     defaults = dict(use_unicode=True, charset=’utf8′, collation=’utf8_general_ci’, autocommit=False)
  125.     for k, v in defaults.iteritems():
  126.         params[k] = kw.pop(k, v)
  127.     params.update(kw)
  128.     params[‘buffered’] = True
  129.     engine = _Engine(lambda: mysql.connector.connect(**params))
  130.     # test connection…
  131.     logging.info(‘Init mysql engine <%s> ok.’ % hex(id(engine)))
  132. class _ConnectionCtx(object):
  133.     ”’
  134.     _ConnectionCtx object that can open and close connection context. _ConnectionCtx object can be nested and only the most 
  135.     outer connection has effect.
  136.     with connection():
  137.         pass
  138.         with connection():
  139.             pass
  140.     ”’
  141.     def __enter__(self):
  142.         global _db_ctx
  143.         self.should_cleanup = False
  144.         if not _db_ctx.is_init():
  145.             _db_ctx.init()
  146.             self.should_cleanup = True
  147.         return self
  148.     def __exit__(self, exctype, excvalue, traceback):
  149.         global _db_ctx
  150.         if self.should_cleanup:
  151.             _db_ctx.cleanup()
  152. def connection():
  153.     ”’
  154.     Return _ConnectionCtx object that can be used by ‘with’ statement:
  155.     with connection():
  156.         pass
  157.     ”’
  158.     return _ConnectionCtx()
  159. def with_connection(func):
  160.     ”’
  161.     Decorator for reuse connection.
  162.     @with_connection
  163.     def foo(*args, **kw):
  164.         f1()
  165.         f2()
  166.         f3()
  167.     ”’
  168.     @functools.wraps(func)
  169.     def _wrapper(*args, **kw):
  170.         with _ConnectionCtx():
  171.             return func(*args, **kw)
  172.     return _wrapper
  173. class _TransactionCtx(object):
  174.     ”’
  175.     _TransactionCtx object that can handle transactions.
  176.     with _TransactionCtx():
  177.         pass
  178.     ”’
  179.     def __enter__(self):
  180.         global _db_ctx
  181.         self.should_close_conn = False
  182.         if not _db_ctx.is_init():
  183.             # needs open a connection first:
  184.             _db_ctx.init()
  185.             self.should_close_conn = True
  186.         _db_ctx.transactions = _db_ctx.transactions + 1
  187.         logging.info(‘begin transaction…’ if _db_ctx.transactions==1 else ‘join current transaction…’)
  188.         return self
  189.     def __exit__(self, exctype, excvalue, traceback):
  190.         global _db_ctx
  191.         _db_ctx.transactions = _db_ctx.transactions – 1
  192.         try:
  193.             if _db_ctx.transactions==0:
  194.                 if exctype is None:
  195.                     self.commit()
  196.                 else:
  197.                     self.rollback()
  198.         finally:
  199.             if self.should_close_conn:
  200.                 _db_ctx.cleanup()
  201.     def commit(self):
  202.         global _db_ctx
  203.         logging.info(‘commit transaction…’)
  204.         try:
  205.             _db_ctx.connection.commit()
  206.             logging.info(‘commit ok.’)
  207.         except:
  208.             logging.warning(‘commit failed. try rollback…’)
  209.             _db_ctx.connection.rollback()
  210.             logging.warning(‘rollback ok.’)
  211.             raise
  212.     def rollback(self):
  213.         global _db_ctx
  214.         logging.warning(‘rollback transaction…’)
  215.         _db_ctx.connection.rollback()
  216.         logging.info(‘rollback ok.’)
  217. def transaction():
  218.     ”’
  219.     Create a transaction object so can use with statement:
  220.     with transaction():
  221.         pass
  222.     >>> def update_profile(id, name, rollback):
  223.     …     u = dict(id=id, name=name, email=’%s@test.org’ % name, passwd=name, last_modified=time.time())
  224.     …     insert(‘user’, **u)
  225.     …     r = update(‘update user set passwd=? where id=?’, name.upper(), id)
  226.     …     if rollback:
  227.     …         raise StandardError(‘will cause rollback…’)
  228.     >>> with transaction():
  229.     …     update_profile(900301, ‘Python’, False)
  230.     >>> select_one(‘select * from user where id=?’, 900301).name
  231.     u’Python’
  232.     >>> with transaction():
  233.     …     update_profile(900302, ‘Ruby’, True)
  234.     Traceback (most recent call last):
  235.       …
  236.     StandardError: will cause rollback…
  237.     >>> select(‘select * from user where id=?’, 900302)
  238.     []
  239.     ”’
  240.     return _TransactionCtx()
  241. def with_transaction(func):
  242.     ”’
  243.     A decorator that makes function around transaction.
  244.     >>> @with_transaction
  245.     … def update_profile(id, name, rollback):
  246.     …     u = dict(id=id, name=name, email=’%s@test.org’ % name, passwd=name, last_modified=time.time())
  247.     …     insert(‘user’, **u)
  248.     …     r = update(‘update user set passwd=? where id=?’, name.upper(), id)
  249.     …     if rollback:
  250.     …         raise StandardError(‘will cause rollback…’)
  251.     >>> update_profile(8080, ‘Julia’, False)
  252.     >>> select_one(‘select * from user where id=?’, 8080).passwd
  253.     u’JULIA’
  254.     >>> update_profile(9090, ‘Robert’, True)
  255.     Traceback (most recent call last):
  256.       …
  257.     StandardError: will cause rollback…
  258.     >>> select(‘select * from user where id=?’, 9090)
  259.     []
  260.     ”’
  261.     @functools.wraps(func)
  262.     def _wrapper(*args, **kw):
  263.         _start = time.time()
  264.         with _TransactionCtx():
  265.             return func(*args, **kw)
  266.         _profiling(_start)
  267.     return _wrapper
  268. def _select(sql, first, *args):
  269.     ‘ execute select SQL and return unique result or list results.’
  270.     global _db_ctx
  271.     cursor = None
  272.     sql = sql.replace(‘?’, ‘%s’)
  273.     logging.info(‘SQL: %s, ARGS: %s’ % (sql, args))
  274.     try:
  275.         cursor = _db_ctx.connection.cursor()
  276.         cursor.execute(sql, args)
  277.         if cursor.description:
  278.             names = [x[0] for x in cursor.description]
  279.         if first:
  280.             values = cursor.fetchone()
  281.             if not values:
  282.                 return None
  283.             return Dict(names, values)
  284.         return [Dict(names, x) for x in cursor.fetchall()]
  285.     finally:
  286.         if cursor:
  287.             cursor.close()
  288. @with_connection
  289. def select_one(sql, *args):
  290.     ”’
  291.     Execute select SQL and expected one result. 
  292.     If no result found, return None.
  293.     If multiple results found, the first one returned.
  294.     >>> u1 = dict(id=100, name=’Alice’, email=’alice@test.org’, passwd=’ABC-12345′, last_modified=time.time())
  295.     >>> u2 = dict(id=101, name=’Sarah’, email=’sarah@test.org’, passwd=’ABC-12345′, last_modified=time.time())
  296.     >>> insert(‘user’, **u1)
  297.     1
  298.     >>> insert(‘user’, **u2)
  299.     1
  300.     >>> u = select_one(‘select * from user where id=?’, 100)
  301.     >>> u.name
  302.     u’Alice’
  303.     >>> select_one(‘select * from user where email=?’, ‘abc@email.com’)
  304.     >>> u2 = select_one(‘select * from user where passwd=? order by email’, ‘ABC-12345’)
  305.     >>> u2.name
  306.     u’Alice’
  307.     ”’
  308.     return _select(sql, True, *args)
  309. @with_connection
  310. def select_int(sql, *args):
  311.     ”’
  312.     Execute select SQL and expected one int and only one int result. 
  313.     >>> n = update(‘delete from user’)
  314.     >>> u1 = dict(id=96900, name=’Ada’, email=’ada@test.org’, passwd=’A-12345′, last_modified=time.time())
  315.     >>> u2 = dict(id=96901, name=’Adam’, email=’adam@test.org’, passwd=’A-12345′, last_modified=time.time())
  316.     >>> insert(‘user’, **u1)
  317.     1
  318.     >>> insert(‘user’, **u2)
  319.     1
  320.     >>> select_int(‘select count(*) from user’)
  321.     2
  322.     >>> select_int(‘select count(*) from user where email=?’, ‘ada@test.org’)
  323.     1
  324.     >>> select_int(‘select count(*) from user where email=?’, ‘notexist@test.org’)
  325.     0
  326.     >>> select_int(‘select id from user where email=?’, ‘ada@test.org’)
  327.     96900
  328.     >>> select_int(‘select id, name from user where email=?’, ‘ada@test.org’)
  329.     Traceback (most recent call last):
  330.         …
  331.     MultiColumnsError: Expect only one column.
  332.     ”’
  333.     d = _select(sql, True, *args)
  334.     if len(d)!=1:
  335.         raise MultiColumnsError(‘Expect only one column.’)
  336.     return d.values()[0]
  337. @with_connection
  338. def select(sql, *args):
  339.     ”’
  340.     Execute select SQL and return list or empty list if no result.
  341.     >>> u1 = dict(id=200, name=’Wall.E’, email=’wall.e@test.org’, passwd=’back-to-earth’, last_modified=time.time())
  342.     >>> u2 = dict(id=201, name=’Eva’, email=’eva@test.org’, passwd=’back-to-earth’, last_modified=time.time())
  343.     >>> insert(‘user’, **u1)
  344.     1
  345.     >>> insert(‘user’, **u2)
  346.     1
  347.     >>> L = select(‘select * from user where id=?’, 900900900)
  348.     >>> L
  349.     []
  350.     >>> L = select(‘select * from user where id=?’, 200)
  351.     >>> L[0].email
  352.     u’wall.e@test.org’
  353.     >>> L = select(‘select * from user where passwd=? order by id desc’, ‘back-to-earth’)
  354.     >>> L[0].name
  355.     u’Eva’
  356.     >>> L[1].name
  357.     u’Wall.E’
  358.     ”’
  359.     return _select(sql, False, *args)
  360. @with_connection
  361. def _update(sql, *args):
  362.     global _db_ctx
  363.     cursor = None
  364.     sql = sql.replace(‘?’, ‘%s’)
  365.     logging.info(‘SQL: %s, ARGS: %s’ % (sql, args))
  366.     try:
  367.         cursor = _db_ctx.connection.cursor()
  368.         cursor.execute(sql, args)
  369.         r = cursor.rowcount
  370.         if _db_ctx.transactions==0:
  371.             # no transaction enviroment:
  372.             logging.info(‘auto commit’)
  373.             _db_ctx.connection.commit()
  374.         return r
  375.     finally:
  376.         if cursor:
  377.             cursor.close()
  378. def insert(table, **kw):
  379.     ”’
  380.     Execute insert SQL.
  381.     >>> u1 = dict(id=2000, name=’Bob’, email=’bob@test.org’, passwd=’bobobob’, last_modified=time.time())
  382.     >>> insert(‘user’, **u1)
  383.     1
  384.     >>> u2 = select_one(‘select * from user where id=?’, 2000)
  385.     >>> u2.name
  386.     u’Bob’
  387.     >>> insert(‘user’, **u2)
  388.     Traceback (most recent call last):
  389.       …
  390.     IntegrityError: 1062 (23000): Duplicate entry ‘2000’ for key ‘PRIMARY’
  391.     ”’
  392.     cols, args = zip(*kw.iteritems())
  393.     sql = ‘insert into `%s` (%s) values (%s)’ % (table, ‘,’.join([‘`%s`’ % col for col in cols]), ‘,’.join([‘?’ for i in range(len(cols))]))
  394.     return _update(sql, *args)
  395. def update(sql, *args):
  396.     r”’
  397.     Execute update SQL.
  398.     >>> u1 = dict(id=1000, name=’Michael’, email=’michael@test.org’, passwd=’123456′, last_modified=time.time())
  399.     >>> insert(‘user’, **u1)
  400.     1
  401.     >>> u2 = select_one(‘select * from user where id=?’, 1000)
  402.     >>> u2.email
  403.     u’michael@test.org’
  404.     >>> u2.passwd
  405.     u’123456′
  406.     >>> update(‘update user set email=?, passwd=? where id=?’, ‘michael@example.org’, ‘654321’, 1000)
  407.     1
  408.     >>> u3 = select_one(‘select * from user where id=?’, 1000)
  409.     >>> u3.email
  410.     u’michael@example.org’
  411.     >>> u3.passwd
  412.     u’654321′
  413.     >>> update(‘update user set passwd=? where id=?’, ‘***’, ‘123\’ or id=\’456′)
  414.     0
  415.     ”’
  416.     return _update(sql, *args)
  417. if __name__==’__main__‘:
  418.     logging.basicConfig(level=logging.DEBUG)
  419.     create_engine(‘www-data’, ‘www-data’, ‘test’)
  420.     update(‘drop table if exists user‘)
  421.     update(‘create table user (id int primary key, name text, email text, passwd text, last_modified real)’)
  422.     import doctest
  423.     doctest.testmod()

这节教程没怎么看懂,不能影响学习进度,继续往下看吧。

 

Python学习:Day 1 – 搭建Web App开发环境

自从开始学习Python,又好久没动过了,在没有实际需要的情况下,拿什么小程序来练手呢?感觉廖雪峰的Python教学博客不错,就参考他博客的实战项目来学习吧。

1、首先,确认系统安装的Python版本是2.7.x:

[root@li1009-80 ~]# python –version
Python 2.7.8

或者
[root@li1009-80 ~]# python -V
Python 2.7.8
[root@li1009-80 ~]#

2、安装开发Web App需要的第三方库:

前端模板引擎jinja2:

[root@li1009-80 ~]# easy_install jinja2

3、安装MySql,已经安装,跳过

4、安装MySQL的Python驱动程序mysql-connector-python:

[root@li1009-80 ~]# easy_install mysql-connector-python

5、建立项目结构

选择一个工作目录,然后,我们建立如下的目录结构:

awesome-python-webapp/   <-- 根目录
|
+- backup/               <-- 备份目录
|
+- conf/                 <-- 配置文件
|
+- dist/                 <-- 打包目录
|
+- www/                  <-- Web目录,存放.py文件
|  |
|  +- static/            <-- 存放静态文件
|  |
|  +- templates/         <-- 存放模板文件
|
+- LICENSE               <-- 代码LICENSE

 

这里作者建议建立好目录后同时建立Git仓库并同步至GitHub,可以保证代码修改的安全,那我就要顺便学习一下Git的用法了,以前只是简单的从GitHub上下载他人的源代码。好在作者还有非常好的Git简明教程

6、Over

使用七牛云存储的QRSBox工具来自动将VPS的数据备份到七牛

使用七牛云存储的QRSBox工具来自动将VPS的数据备份到七牛

这个工具的好处就是初始化之后可以自动检测备份目录,并将文件上传到七牛,更重要的是支持windows和linux平台,这里主要是介绍linux系统下的备份方法,因为小z的VPS安装的是AMH面板,所以就用AMH来做介绍了。不过原理都是互通的,大家可以参照。

1、建立文件夹qiniu,并进入qiniu目录

[root@li1009-80 home]# mkdir qiniu

[root@li1009-80 home]# cd qiniu/

[root@li1009-80 qiniu]#

2、下载七牛的工具Qrsbox

[root@li1009-80 qiniu]#wget http://devtools.qiniu.io/qiniu-devtools-linux_amd64-current.tar.gz

32位的用户请输入”wget http://devtools.qiniu.io/qiniu-devtools-linux_386-current.tar.gz”进行下载

3、解压下载的文件

[root@li1009-80 qiniu]# ls
qiniu-devtools-linux_amd64-current.tar.gz
[root@li1009-80 qiniu]# tar -zxvf qiniu-devtools-linux_amd64-current.tar.gz

4、在七牛云存储里新建一个bucket(空间),将属性设置为私有(为了数据的安全起见)

Snip20150520_4

5、然后,在解压后的文件夹中执行以下命令,进行初始化:

Snip20150520_7

命令解释:

 ./qrsboxcli init <AccessKey> <SecretKey> <SyncDir> <Bucket> [<KeyPrefix>]

其中,<AccessKey> 和 <SecretKey> 是七牛云存储的密钥文件,<SyncDir> 是本地的同步目录,该目录下的文件会随时同步上传值七牛云存储。<Bucket> 是保存同步文件的资源空间名。<KeyPrefix> 是文件前缀,可选。如果设置了该参数,那么上传的文件名前都会加上前缀。这个前缀主要用于在空间中区分不同上传来源的文件。

获取七牛秘钥是在这里面:

Snip20150520_8

6、使用以下命令开始文件同步:

[root@li1009-80 qiniu]# ./qrsboxcli sync &

七牛的QrsBox工具会自动同步到bucket,备份成功后我们可以在七牛的后台进行查看。

 更多用法请看官方文档