1 开发环境技术:B/S(.NET C# )
2、Microsoft Visual Studio 2013 C#.NET
3、.NET Framework 4.0及以上 (支援最新4.5版本)
4、
SQL Server 2008 R2及以上 (支援2012/2014)框架特点
2 系统简介
1、帮企业快速地实现各种通用功能,结合系统现有的通用权限管理功能。
2、快速地开发出各种项目应用系统。让企业开发一个系统变得非常轻松。
3、符合RBAC 灵活不仅符合国际通用标准,又能满足国内的大中小型软件项目的灵活设置需求。
4、文档齐全支持二次开发提供完善的接口函数调用说明、开放接口、开放源码、开放
数据库结构设计。
5、分层理念 SOA理念程序可以采用不同的实施策略、架构需求、方便维护、方便扩展。
6、有价值且优秀的产品,这样您就有了市场需求了。
7、适用于OA、网站、电子政务、ERP、CRM等基于B/S架构的应用软件系统的快速开发框架。
3 系统应用价值
避免重复开发,降低开发成本,权限模块是每个应用系统的不可缺少的部分,但每个客户对权限管理的需求却不完全相同。 如果按需从头分析和设计,必将造成重复开发。BPMS通用基本权限系统针对不同应用系统设计, 提供用户、角色权限模块的基础框架和通用模型,帮助开发者快速实施和开发出符合不同需求的用户权限管理模块。 能够最大程度降低开发
工作量,节约开发成本。
3.1 产品优点体系
1、通用权限管理系统其中最重要的思路就是把常用的模块封装成控件进行重复使用,一则可以避免重复开发,提高开发效率,它能缩短开发时间,减少代码量,使开发者更专注于业务和服务端,轻松实现界面开发,带来绝佳的用户体验,适用于OA、网站、电子政务、ERP、CRM等基于B/S架构的应用软件系统的快速开发框架。
2、角色权限分配与用户权限分配相结合,融合了角色的权限管理的统一便捷性和用户权限分配的灵活性。
3、强大的数据权限管理,实现了单笔数据的权限分配。
4、细粒度的权限管控,权限分配能精确到界面上的每一个功能按钮。
5、实现简易的单点登录功能,用户只要记住一对用户名密码就可以。
6、多个管理系统可以用统一的一套后台管理工具进行管理。
7、二次开发简单,几分钟即可部署一个系统(快速、简单、高效、安全、可靠)、编码简单易懂、注释详细。
3.2 全新的技术架构
1、本套框架涵盖了ASP.NET4.0、ASP.NET MVC 5.0、WebAPI、WCF、WEB Pages、SignalR、WF、AJAX、EntityFramework、IOC、AOP和SSB等。解决在开发中经常用到的日志、缓存、异常、事务、多浏览器支持、通用权限、安全、加密解密、压缩解压。实现基于XML的动态配置,JS脚本、CSS样式、图片文件支持动态配置,解决通常用到的打印、报表、图标、导入和导出等功能。
2、采用Ajax技术交互,带来良好的用户体验。
3、界面简洁大方,加载迅速。
4、结合CodeSmith代码模板生成器快速开发系统、
5、浏览器支持:IE8、IE9、IE10、firefox 、Chrome、
360、 Safari、Opera、傲游、搜狗、世界之窗。
6、内置模块 :基本权限关系系统,CRM、OA、进销存和业务管理系统
7、采用 WEB FORM、MVC、SignalR和WebAPI同一ASP.NET的框架模式,具有耦合性低、重用性高、生命周期成本低、可维护性高、有利软件工程化管理等优点
8、采用WebAPI,客户端完全摆脱了代理和管道来直接进行交互
9、采用标准CSS前台UI界面,可轻松的打造出功能丰富并且美观的UI界面
10、数据访问层采用强大的Ghd.Net Framework框架完美地支持数据库操作
11、提供多种丰富的组件,封装了一大部分比较实用的控件和组件,如自动完成控件、弹出控件、拼音模糊输入控件、日期控件My97DatePicker、导出组件、Jquery、 AjaxToolkit、 AntiXss、 AspNetPage、 Dundas、 EnterpriseLib、 Grid++Report 5.0 、 JSON、 NPOI、 Quartz.Net、Telerik UI for ASP.NET AJAX 和 Telerik UI for ASP.NET MVC等。
3.3 高度可扩展性和灵活性
1、动态表单管理,灵活配置减少因需求变更带来的开发工作。
3、系统菜单灵活配置,并和权限系统进行关联。
3.4 丰富的系统功能
1、数据库资源管理,不用登陆数据直接在页面上进行数据库管理、数据定时备份
2、操作日志生成
3、动态接口管理,动态配置WCF接口,无须开发实现即可提供WCF接口
4、系统访问控件,限制指定IP对系统的访问
3.5 优秀的用户体验
1、通用权限系统为最终用户提供全可视化的操作界面,轻松管理维护用户权限和用户相关数据。
2、超高效配置系统,从新增应用系统到配置完成最快只需几分钟。
3、界面异步刷新,操作性能优秀,提供更佳的用户体验。
4、提供用户数据图表统计和操作日志。
4 功能描述
1.菜单导航管理
2.操作按钮
3.角色管理
4.部门管理
5.用户管理(用户权限))
6.系统配置(动态配置系统参数)
7.系统日志(异常记录)
8.数据库备份/还原
9.数据回收站(业务功能删除过数据,全部保留在回收站)
5 产品适用对象与用户群体
1、大中小型软件开发公司,技术支持、技术咨询公司。
2、管理类软件开发者。
3、想进一步提升自身技术能力的开发者、学生等。
4、培训教程、大学课外、员工培训。
5、政府机关、事业单位、集团公司。
6、企业、工厂等。
数据库结构如下图:
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
但是包嵌入到
Python中的只有轻量级数据库SQLite,所以不用安装SQLite数据库操作包(但要安装数据库软件, 此处我犯错误了)。其他的必须安装。同时也要安装数据库软件。
先讲解下DB-API。因为数据库类型实在太多太杂,所以就出现了SGI小组,为不同的数据库提供一致的访问接口即DB-API,可以在不同数据库间快速移植代码。
比如Python开发的MySQLdb遵从DB-API, 实现了connect(), connect.cursor()等方法...其他的db类也实现了同样的方法,故可以很容易移植。
DB-API规范的属性:
apilevel DB-API 模块兼容的 DB-API 版本号
threadsafety 线程安全级别
paramstyle 该模块支持的
SQL 语句参数风格
DB-API规范的方法:
connect() 连接函数,生成一个connect对象,以提供数据库操作,同事函数参数也是固定好的
其中connect对象又有如下方法:
#所谓事务可以认为是一整套操作 只要有一处纰漏就废
close():关闭此connect对象, 关闭后无法再进行操作,除非再次创建连接
commit():提交当前事务,如果是支持事务的数据库执行增删改后没有commit则数据库默认回滚,白操作了
rollback():取消当前事务
cursor():创建游标对象
其中cursor游标对象又有如下属性和方法:
常用方法:
close():关闭此游标对象
fetchone():得到结果集的下一行
fetchmany([size = cursor.arraysize]):得到结果集的下几行
fetchall():得到结果集中剩下的所有行
excute(sql[, args]):执行一个数据库查询或命令
excutemany(sql, args):执行多个数据库查询或命令
常用属性:
connection:创建此游标对象的数据库连接
arraysize:使用fetchmany()方法一次取出多少条记录,默认为1
lastrowid:相当于PHP的last_inset_id()
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
前一段时间由于开题的事情一直耽搁了我搞
Linux的进度,搞的我之前学的东西都遗忘了,非常烦躁的说,如今抽个时间把之前所学的做个小节。
文章内容主要总结于《Linux程序设计第3版》。
1.Linux进程与线程
Linux进程创建一个新线程时,线程将拥有自己的栈(由于线程有自己的局部变量),但与它的创建者共享全局变量、文件描写叙述符、信号句柄和当前文件夹状态。
Linux通过fork创建子进程与创建线程之间是有差别的:fork创建出该进程的一份拷贝,这个新进程拥有自己的变量和自己的PID,它的时间调度是独立的,它的运行差点儿全然独立于父进程。
进程能够看成一个资源的基本单位,而线程是程序调度的基本单位,一个进程内部的线程之间共享进程获得的时间片。
2._REENTRANT宏
在一个多线程程序里,默认情况下,仅仅有一个errno变量供全部的线程共享。在一个线程准备获取刚才的错误代码时,该变量非常easy被还有一个线程中的函数调用所改变。相似的问题还存在于fputs之类的函数中,这些函数通经常使用一个单独的全局性区域来缓存输出数据。
为解决问题,须要使用可重入的例程。可重入代码能够被多次调用而仍然
工作正常。编写的多线程程序,通过定义宏_REENTRANT来告诉编译器我们须要可重入功能,这个宏的定义必须出现于程序中的不论什么#include语句之前。
_REENTRANT为我们做三件事情,而且做的很优雅:
(1)它会对部分函数又一次定义它们的可安全重入的版本号,这些函数名字一般不会发生改变,仅仅是会在函数名后面加入_r字符串,如函数名gethostbyname变成gethostbyname_r。
(2)stdio.h中原来以宏的形式实现的一些函数将变成可安全重入函数。
(3)在error.h中定义的变量error如今将成为一个函数调用,它可以以一种安全的多线程方式来获取真正的errno的值。
3.线程的基本函数
大多数pthread_XXX系列的函数在失败时,并未遵循UNIX函数的惯例返回-1,这样的情况在UNIX函数中属于一少部分。假设调用成功,则返回值是0,假设失败则返回错误代码。
1).线程创建:
#include <pthread.h>
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
參数说明:
thread:指向pthread_create类型的指针,用于引用新创建的线程。
attr:用于设置线程的属性,一般不须要特殊的属性,所以能够简单地设置为NULL。
*(*start_routine)(void *):传递新线程所要运行的函数地址。
arg:新线程所要运行的函数的參数。
调用假设成功,则返回值是0,假设失败则返回错误代码。
2).线程终止
#include <pthread.h>
void pthread_exit(void *retval);
參数说明:
retval:返回指针,指向线程向要返回的某个对象。
线程通过调用pthread_exit函数终止运行,并返回一个指向某对象的指针。注意:绝不能用它返回一个指向局部变量的指针,由于线程调用该函数后,这个局部变量就不存在了,这将引起严重的程序漏洞。
3).线程同步
#include <pthread.h>
int pthread_join(pthread_t th, void **thread_return);
參数说明:
th:将要等待的张璐,线程通过pthread_create返回的标识符来指定。
thread_return:一个指针,指向还有一个指针,而后者指向线程的返回值。
一个简单的多线程Demo(thread1.c):
编译这个程序时,须要定义宏_REENTRANT:
gcc -D_REENTRANT thread1.c -o thread1 –lpthread
执行这个程序:
$ ./thread1输出:
thread_function is running. Argument was Hello World
Waiting for thread to finish...
Thread joined, it returned Thank you for your CPU time!
Message is now Bye!
这个样例值得我们去花时间理解,由于它将作为几个样例的基础。
pthread_exit(void *retval)本身返回的就是指向某个对象的指针,因此,pthread_join(pthread_t th, void **thread_return);中的thread_return是二级指针,指向线程返回值的指针。
能够看到,我们创建的新线程改动的数组message的值,而原先的线程也能够訪问该数组。假设我们调用的是fork而不是pthread_create,就不会有这种效果了。原因是fork创建子进程之后,子进程会拷贝父进程,两者分离,相互不干扰,而线程之间则是共享进程的相关资源。
4.线程的同一时候运行
接下来,我们来编写一个程序,以验证两个线程的运行是同一时候进行的。当然,假设是在一个单处理器系统上,线程的同一时候运行就须要靠CPU在线程之间的高速切换来实现了。
我们的程序须要利用一个原理:即除了局部变量外,全部其它的变量在一个进程中的全部线程之间是共享的。
在这个程序中,我们是在两个线程之间使用轮询技术,这样的方式称为忙等待,所以它的效率会非常低。在本文的兴许部分,我们将介绍一种更好的解决的方法。
以下的代码中,两个线程会不断的轮询推断flag的值是否满足各自的要求。
编译这个程序:
gcc -D_REENTRANT thread2.c -o thread2 –lpthread
执行这个程序:
$ ./thread2
121212121212121212
Waiting for thread to finish...
5.线程的同步
在上述演示样例中,我们採用轮询的方式在两个线程之间不停地切换是很笨拙且没有效率的实现方式,幸运的是,专门有一级设计好的函数为我们提供更好的控制线程运行和訪问代码临界区的方法。
本小节将介绍两个线程同步的基本方法:信号量和相互排斥量。这两种方法非常类似,其实,它们能够互相通过对方来实现。但在实际的应用中,对于一些情况,可能使用信号量或相互排斥量中的一个更符合问题的语义,而且效果更好。
5.1用信号量进行同步
1.信号量创建
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
參数说明:
sem:信号量对象。
pshared:控制信号量的类型,0表示这个信号量是当前进程的局部信号量,否则,这个信号量就能够在多个进程之间共享。
value:信号量的初始值。
2.信号量控制
#include <semaphore.h>
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);
sem_post的作用是以原子操作的方式给信号量的值加1。
sem_wait的作用是以原子操作的方式给信号量的值减1,但它会等到信号量非0时才会開始减法操作。假设对值为0的信号量调用sem_wait,这个函数就会等待,直到有线程添加了该信号量的值使其不再为0。
3.信号量销毁
#include <semaphore.h>
int sem_destory(sem_t *sem);
这个函数的作用是,用完信号量后对它进行清理,清理该信号量所拥有的资源。假设你试图清理的信号量正被一些线程等待,就会收到一个错误。
与大多数Linux函数一样,这些函数在成功时都返回0。
以下编码实现输入字符串,统计每行的字符个数,以“end”结束输入:
编译这个程序:
gcc -D_REENTRANT thread2.c -o thread2 –lpthread
执行这个程序:
$ ./thread3 Input some text. Enter 'end' to finish 123 You input 3 characters 1234 You input 4 characters 12345 You input 5 characters end Waiting for thread to finish… Thread join |
通过使用信号量,我们堵塞了统计字符个数的线程,这个程序似乎对高速的文本输入和悠闲的暂停都非常适用,比之前的轮询解决方式效率上有了本质的提高。 5.2用相互排斥量进行线程同步
还有一种用在多线程程序中同步訪问的方法是使用相互排斥量。它同意程序猿锁住某个对象,使得每次仅仅能有一个线程訪问它。为了控制对关键代码的訪问,必须在进入这段代码之前锁住一个相互排斥量,然后在完毕操作之后解锁它。
用于相互排斥量的基本函数和用于信号量的函数很类似:
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t, *mutexattr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destory(pthread_mutex_t *mutex);
与其它函数一样,成功时返回0,失败时将返回错误代码,但这些函数并不设置errno,所以必须对函数的返回代码进行检查。相互排斥量的属性设置这里不讨论,因此设置成NULL。
我们用相互排斥量来重写刚才的代码例如以下:
编译这个程序:
gcc -D_REENTRANT thread4.c -o thread4 –lpthread
执行这个程序:
$ ./thread4 Input some text. Enter 'end' to finish 123 You input 3 characters 1234 You input 4 characters 12345 You input 5 characters end You input 3 characters Thread joined |
6.线程的属性
之前我们并未谈及到线程的属性,能够控制的线程属性是许多的,这里面仅仅列举一些经常使用的。
如在前面的演示样例中,我们都使用的pthread_join同步线程,但事实上有些情况下,我们并不须要。如:主线程为服务线程,而第二个线程为数据备份线程,备份工作完毕之后,第二个线程能够直接终止了,它没有必要再返回到主线程中。因此,我们能够创建一个“脱离线程”。
以下介绍几个经常使用的函数:
(1)int pthread_attr_init (pthread_attr_t* attr);
功能:对线程属性变量的初始化。
attr:线程属性。
函数返回值:成功:0,失败:-1
(2) int pthread_attr_setscope (pthread_attr_t* attr, int scope);
功能:设置线程绑定属性。
attr:线程属性。
scope:PTHREAD_SCOPE_SYSTEM(绑定);PTHREAD_SCOPE_PROCESS(非绑定)
函数返回值:成功:0,失败:-1
(3) int pthread_attr_setdetachstate (pthread_attr_t* attr, int detachstate);
功能:设置线程分离属性。
attr:线程属性。
detachstate:PTHREAD_CREATE_DETACHED(分离);PTHREAD_CREATE_JOINABLE(非分离)
函数返回值:成功:0,失败:-1
(4) int pthread_attr_setschedpolicy(pthread_attr_t* attr, int policy);
功能:设置创建线程的调度策略。
attr:线程属性;
policy:线程调度策略:SCHED_FIFO、SCHED_RR和SCHED_OTHER。
函数返回值:成功:0,失败:-1
(5) int pthread_attr_setschedparam (pthread_attr_t* attr, struct sched_param* param);
功能:设置线程优先级。
attr:线程属性。
param:线程优先级。
函数返回值:成功:0,失败:-1
(6) int pthread_attr_destroy (pthread_attr_t* attr);
功能:对线程属性变量的销毁。
attr:线程属性。
函数返回值:成功:0,失败:-1
(7)其它
int pthread_attr_setguardsize(pthread_attr_t* attr,size_t guardsize);//设置新创建线程栈的保护区大小。
int pthread_attr_setinheritsched(pthread_attr_t* attr, int inheritsched);//决定如何设置新创建线程的调度属性。
int pthread_attr_setstack(pthread_attr_t* attr, void* stackader,size_t stacksize);//两者共同决定了线程栈的基地址以及堆栈的最小尺寸(以字节为单位)。
int pthread_attr_setstackaddr(pthread_attr_t* attr, void* stackader);//决定了新创建线程的栈的基地址。
int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stacksize);//决定了新创建线程的栈的最小尺寸(以字节为单位)。
例:创建优先级为10的线程。
pthread_attr_t attr; struct sched_param param; pthread_attr_init(&attr); pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM); //绑定 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); //分离 pthread_attr_setschedpolicy(&attr, SCHED_RR); param.sched_priority = 10; pthread_attr_setschedparam(&attr, ¶m); pthread_create(xxx, &attr, xxx, xxx); pthread_attr_destroy(&attr); |
以下实现一个脱离线程的程序,创建一个线程,其属性设置为脱离状态。子线程结束时,要使用pthread_exit,原来的主线程不再等待与子线程又一次合并。代码例如以下:
编译这个程序:
gcc -D_REENTRANT thread5.c -o thread5 –lpthread
执行这个程序:
$ ./thread5
thread_function is running. Argument: hello world!
Waiting for thread to finished...
Waiting for thread to finished...
Waiting for thread to finished...
Waiting for thread to finished...
Second thread setting finished flag, and exiting now
Other thread finished!
通过设置线程的属性,我们还能够控制线程的调试,其方式与设置脱离状态是一样的。
7.取消一个线程
有时,我们想让一个线程能够要求还有一个线程终止,线程有方法做到这一点,与信号处理一样,线程能够在被要求终止时改变其行为。
先来看用于请求一个线程终止的函数:
#include <pthread.h>
int pthread_cancel(pthread_t thread);
这个函数简单易懂,提供一个线程标识符,我们就能够发送请求来取消它。
线程能够用pthread_setcancelstate设置自己的取消状态。
#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
參数说明:
state:能够是PTHREAD_CANCEL_ENABLE同意线程接收取消请求,也能够是PTHREAD_CANCEL_DISABLE忽略取消请求。
oldstate:获取先前的取消状态。假设对它没兴趣,能够简单地设置为NULL。假设取消请求被接受了,线程能够进入第二个控制层次,用pthread_setcanceltype设置取消类型。
#include <pthread.h>
int pthread_setcanceltype(int type, int *oldtype);
參数说明:
type:能够取PTHREAD_CANCEL_ASYNCHRONOUS,它将使得在接收到取消请求后马上採取行动;还有一个是PTHREAD_CANCEL_DEFERRED,它将使得在接收到取消请求后,一直等待直到线程运行了下述函数之中的一个后才採取行动:pthread_join、pthread_cond_wait、pthread_cond_timedwait、pthread_testcancel、sem_wait或sigwait。
oldtype:同意保存先前的状态,假设不想知道先前的状态,能够传递NULL。
默认情况下,线程在启动时的取消状态为PTHREAD_CANCEL_ENABLE,取消类型是PTHREAD_CANCEL_DEFERRED。
以下编写代码thread6.c,主线程向它创建的线程发送一个取消请求。
编译这个程序:
gcc -D_REENTRANT thread6.c -o thread6 –lpthread
执行这个程序:
$ ./thread6
thread_function is running...
Thread is still running (0)...
Thread is still running (1)...
Thread is still running (2)...
Thread is still running (3)...
Canceling thread...
Waiting for thread to finished...
8.多线程
之前,我们所编写的代码里面都不过创建了一个线程,如今我们来演示一下怎样创建一个多线程的程序。
编译这个程序:
gcc -D_REENTRANT thread7.c -o thread7 –lpthread
执行这个程序:
$ ./thread7 thread_function is running. Argument was 0 thread_function is running. Argument was 1 thread_function is running. Argument was 2 thread_function is running. Argument was 3 thread_function is running. Argument was 4 Bye from 1 thread_function is running. Argument was 5 Waiting for threads to finished... Bye from 5 Picked up a thread:6 Bye from 0 Bye from 2 Bye from 3 Bye from 4 Picked up a thread:5 Picked up a thread:4 Picked up a thread:3 Picked up a thread:2 Picked up a thread:1 All done |
9.小结
本文主要介绍了Linux环境下的多线程编程,介绍了信号量和相互排斥量、线程属性控制、线程同步、线程终止、取消线程及多线程并发。
本文比較简单,仅仅作为初学Linux多线程编程入门之用。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
一、 背景
SQL Server,如果我们需要把数据库A的所有表数据到数据库B中,通常我们会怎么做呢?我会使用SSMS的导入导出功能,进行表数据的导入导出,无可厚非,这样的导入非常简单和方便;
但是,当我们的表有上百个,而且有些表是有自增ID的,那么这个时候使用SSMS的话,你需要一个个手动设置(如图1),你要知道,需要设置上百个的这些选项是件多么痛苦的事情,而且最后很可能会因为外键约束导致导入导出失败。
(图1)
虽然SSMS在导入导出的最后一步提供了生成SSIS包的功能,但是对于转移数据的需求来说,还是无法达到我想要的快速、方便。
自然而然,我想到了INSERT INTO XX SELECT FROM XX WHERE这样的方式(这种方式的好处就是可以对数据记录、字段进行控制),但是如何才能快速生成整个
数据库所有表的这些语句呢?
假如你需要批量生成下面的SQL,我想这篇
文章就可以帮到你了:
--[OpinionList]
SET IDENTITY_INSERT [master_new].[dbo].[OpinionList] ON
INSERT INTO [master_new].[dbo].[OpinionList](Id,Batch,LinkId,DB_Names,CreateTime)
SELECT * FROM [DBA_DB].[dbo].[OpinionList]
SET IDENTITY_INSERT [master_new].[dbo].[OpinionList] OFF
GO
二、 脚本解释
(一) 我编写了一个模板,这个模板你只需要设置@fromdb和@todb的名称,这样就会生成从@fromdb导出所有表插入到@todb中的SQL语句,需要注意的是:要选择@fromdb对应的数
据库执行模板SQL,不然无法生成需要的表和字段。 DECLARE @fromdb VARCHAR(100) DECLARE @todb VARCHAR(100) DECLARE @tablename VARCHAR(100) DECLARE @columnnames NVARCHAR(300) DECLARE @isidentity NVARCHAR(30) DECLARE @temsql NVARCHAR(max) DECLARE @sql NVARCHAR(max) SET @fromdb = 'master' SET @todb = 'master_new' --游标 DECLARE @itemCur CURSOR SET @itemCur = CURSOR FOR SELECT '['+[name]+']' from sys.tables WHERE type='U' order by name OPEN @itemCur FETCH NEXT FROM @itemCur INTO @tablename WHILE @@FETCH_STATUS=0 BEGIN SET @sql = '' |
--获取表字段 SET @temsql = N' BEGIN SET @columnnamesOUT ='''' SELECT @columnnamesOUT = @columnnamesOUT + '','' + name From sys.columns where object_id=OBJECT_ID(''['+@fromdb+'].dbo.'+@tablename+''') order by column_id SELECT @columnnamesOUT=substring(@columnnamesOUT,2,len(@columnnamesOUT)) END ' EXEC sp_executesql @temsql,N'@columnnamesOUT NVARCHAR(300) OUTPUT',@columnnamesOUT=@columnnames OUTPUT PRINT ('--'+@tablename) --判断是否有自增字段 SET @temsql = N' BEGIN SET @isidentityOUT ='''' SELECT @isidentityOUT = name From sys.columns where object_id=OBJECT_ID(''['+@fromdb+'].dbo.'+@tablename+''') and is_identity = 1 END ' EXEC sp_executesql @temsql,N'@isidentityOUT NVARCHAR(30) OUTPUT',@isidentityOUT=@isidentity OUTPUT --IDENTITY_INSERT ON IF @isidentity != '' BEGIN SET @sql = 'SET IDENTITY_INSERT ['+@todb+'].[dbo].['+@tablename+'] ON ' END --INSERT SET @sql = @sql+'INSERT INTO ['+@todb+'].[dbo].['+@tablename+']('+@columnnames+') SELECT * FROM ['+@fromdb+'].[dbo].['+@tablename+']' --IDENTITY_INSERT OFF IF @isidentity != '' BEGIN SET @sql = @sql+' SET IDENTITY_INSERT ['+@todb+'].[dbo].['+@tablename+'] OFF' END --返回SQL PRINT(@sql)PRINT('GO')+CHAR(13) FETCH NEXT FROM @itemCur INTO @tablename END CLOSE @itemCur DEALLOCATE @itemCur |
(二) 下面就是返回的生成的部分脚本,模板会自动判断表是否存在自增字段,如果存在就会生成对应的IDENTITY_INSERT语句。
--spt_values INSERT INTO [master_new].[dbo].[spt_values](name,number,type,low,high,status) SELECT * FROM [master].[dbo].[spt_values] GO --[OpinionList] SET IDENTITY_INSERT [master_new].[dbo].[OpinionList] ON INSERT INTO [master_new].[dbo].[OpinionList](Id,Batch,LinkId,DB_Names,CreateTime) SELECT * FROM [DBA_DB].[dbo].[OpinionList] SET IDENTITY_INSERT [master_new].[dbo].[OpinionList] OFF GO |
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
replace和replaceAll是JAVA中常用的替换字符的方法,它们的区别是: 1)replace的参数是char和CharSequence,即可以支持字符的替换,也支持字符串的替换(CharSequence即字符串序列的意思,说白了也就是字符串);
2)replaceAll的参数是regex,即基于规则表达式的替换,比如,可以通过replaceAll("\\d", "*")把一个字符串所有的数字字符都换成星号;
相同点是都是全部替换,即把源字符串中的某一字符或字符串全部换成指定的字符或字符串,如果只想替换第一次出现的,可以使用 replaceFirst(),这个方法也是基于规则表达式的替换,但与replaceAll()不同的是,只替换第一次出现的字符串;
另外,如果replaceAll()和replaceFirst()所用的参数据不是基于规则表达式的,则与replace()替换字符串的效果是一样的,即这两者也支持字符串的操作;
还有一点注意:执行了替换操作后,源字符串的内容是没有发生改变的.
举例如下:
String src = new String("ab43a2c43d"); System.out.println(src.replace("3","f"));=>ab4f2c4fd. System.out.println(src.replace('3','f'));=>ab4f2c4fd. System.out.println(src.replaceAll("\\d","f"));=>abffafcffd. System.out.println(src.replaceAll("a","f"));=>fb43fc23d. System.out.println(src.replaceFirst("\\d,"f"));=>abf32c43d System.out.println(src.replaceFirst("4","h"));=>abh32c43d. |
如何将字符串中的"\"替换成"\\":
String msgIn;
String msgOut;
msgOut=msgIn.replaceAll("\\\\",\\\\\\\\);
ps:貌似这样也可以:msgIn = msgIn.replaceAll("\\\\",\\\\\\\\);
原因:
'\'在java中是一个转义字符,所以需要用两个代表一个。例如System.out.println( "\\" ) ;只打印出一个"\"。但是'\'也是正则表达式中的转义字符(replaceAll 的参数就是正则表达式),需要用两个代表一个。所以:\\\\被java转换成\\,\\又被正则表达式转换成\。
同样
CODE: \\\\\\\\
Java: \\\\
Regex: \\
将字符串中的'/'替换成'\'的几种方式:
msgOut= msgIn.replaceAll("/", "\\\\");
msgOut= msgIn.replace("/", "\\");
msgOut= msgIn.replace('/', '\\');
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
摘要:
IT行业已经发展了几十年,但如何成为一个优秀的IT项目经理?这个问题还在困扰着很多人。本文结合自己的实践经验和理论研究,针对中国国情,论述了IT项目经理基础知识体系的重要性,指出了IT项目经理应具备的知识体系和个性特征。
本节对于项目管理资深人士属于啰嗦,但笔者慎重思考后还是认为有必要啰嗦几句,因为错误的观念依然在传播,毒害不知真相的人。只有让正确的观点流行传播,让大家了解真相,才能少走弯路,减少错误,使得更多人用宝贵的时间做更有意义的事。
有一种观念在我国非常流行:项目经理是干出来的,不是考出来的;PMBOK是老外整出来的东西,内容根本就是花架子,不适合国情,拿PMP纯粹是糊弄人,耽搁时间。其实还有很多类似的观点在广泛传播,比如大学生无用论,MBA无用论,其根本就是没有辨清知识体系与能力之间的关系,而不明真相,缺少判断力的人只看结果,让这些似是而非的错误观念到处传播,到处发毒。这种毒对年轻人毒害尤其大!
项目管理也是管理,管理的对象主要包括两个:人和事,主要是人。虽然有东西方文化差异,但是人性是相通的,尤其是现在全球化日益深入的情况下,在同一个项目中同时存在东西方文化和不同国籍组员的情况日益普遍,而管理思想深层次折射的是文化。对于刻意突出“西方管理不适合中国土壤”的人,除了要以“语不惊人死不休”的表达方式来体现他的真知灼见外,同时也反映了这些人某些层面的浅薄:用地域和群体来表述必然会以偏概全!
获得PMP不一定就完全掌握了PMBOK,这跟一个大学毕业生拿到学士学位,对大学某一专业的知识体系有了全面了解,但毕业后却不一定就能成为该专业领域的优秀人才一样:知道不一定能做到!
学习知识,需要的是记忆和分析能力,主要是记忆;而每个人的实际能力却跟个人的天赋有很大关系。掌握PMBOK,明白项目管理该做些什么,其中的方法论也具体指导你某些事该怎么做,但真正的管理项目,却需要根据实际情况灵活判断该采用哪些知识、哪些方法来处理。再举个大家更熟悉的例子,一个学习了PMBOK并获得PMP的人,就好比一个精读并熟记了“葵花宝典”的书生,能否成为“东方不败”,这一方面要靠自己的天赋,另一方面真的需要苦练,甚至挥刀自宫的酷刑(得摒弃自己性格中的某些缺陷,比如一个自由散漫的人一定得学会自律,才可能成为一个优秀的项目经理)。
PMBOK包含5大过程,9大知识领域,集成了全球项目经理人丰富的最佳实践,称之为《项目管理的“葵花宝典”》毫不夸张。最为关键的是,PMBOK在不断更新完善,新的最佳实践和知识在不断对其充实。PMI的认证体系根据项目管理岗位,管理能力和管理范围的不同需要进行了分级:CPMP(项目经理助理)、PMP(项目经理)、PgMP(高级项目经理)。不同的
工作岗位需要不同的知识体系。据最新获得的消息,PMBOK在今后的版本中很有可能根据行业不同分出不同行业的PMBOK,我们将会看到建筑行业的PMBOK,IT行业的PMBOK,制造业的PMBOK……,这是集体智慧的结晶,并且在不断融入新的智慧!
知道了不一定能做到,但是根本不知道,你认为能做到么?
明白了以上的关系,PMBOK我们要不要去读?PMP认证我们该不该拿?这个你自己决定。“要练神功,先要自宫”,可能会吓跑不想获得神功的人,但吓不跑“东方不败”!
二、IT项目经理应具备的知识体系
比较流行的观念是,IT项目经理需要三方面的知识:IT专业知识、业务知识、管理知识。这是国内企业对战斗在一线的项目经理的普遍要求,尤其是软件项目的PM。
什么样的人才适合项目管理的职责?“从理论上,具体到特定的项目任务,谁更有可能取得项目成功,谁就应该承担项目管理的职责。”这是一个相当骑墙的答案,但说出了本质。项目经理的任命,项目经理应该具备的知识体系,完全是由具体项目任务决定的。
对于单个的中小软件项目,国内多数企业都是以1个项目经理+N(0~12)个开发人员这样的团队进行任命组建,而为了压缩成本,多数开发人员都是刚毕业或者有短暂开发经验的年轻技术人员,项目所需的知识要求,可能多数都集中在了项目经理一个人身上。而多数这样的项目经理,从公司的角度,要求的是经验,有过1个或几个同类项目的开发经验,是编程高手,懂一些系统分析设计和
数据库设计的知识即可,而对管理的要求,只要你能带好几个人干活就行。
这是普遍现象,也有把项目做成功的,但失败率很高,失败的项目问题出在什么地方?如果说责任,可以说是企业任命错误,也可以说项目经理本人能力不足。但作为个人,项目经理如果不能认识到自己的不足,那注定不可能有进步和提升。
因为业务性质的不同,IT项目所需知识差异很大,但可以总括为软硬件知识、网络知识、美术知识、业务知识、管理知识。其中软件知识领域会包含
操作系统、应用服务器、数据库、编程(语言、算法和数据结构、设计模式)、软件工程等。
而管理知识,没学过项目管理的软件专业人士多数都熟悉软件工程,其中有很多管理思想,但是软件工程的管理不同于项目管理,有哪些差异请参阅乔东的
文章《IT产品管理与项目管理的关系》。
“麻雀虽小,五脏俱全”。任何一个IT项目,都会涉及到以上所有知识领域,随着项目的增大相应的知识领域复杂度会更大。很难有一个人精通以上所有知识,因为这些知识随着创新还在不断的增加。现在极个别情况下还有一个人开发一个软件项目的情况,但这样的情形越来越少。多数项目失败,都是因为项目组知识体系不健全导致,可能是技术知识,也可能是管理知识。
国内很多软件项目的项目经理是由程序员提拔上来,如果他对软件工程掌握得比较好,对某些简单的软件项目,基于过去项目的经验,可能会成功,这也是很多人认“项目经理是干出来,不是学出来”的理由。这样的项目经理如果面对多个子项目,功能复杂,干系人复杂,时间要求紧等复杂情况时,必然会因为知识体系的不健全,越来越多的问题不知道如何处理,不能很好的预测项目风险,随着项目的开展,使局面混乱复杂,最终导致项目失败。
还有一个让很多人困惑的问题是,一个完全不懂IT技术的人是否可以做IT项目经理?对此的答案是很明确的:这跟“什么样的人才适合项目管理的职责?”答案相同,如果他能使项目成功,就是可以。项目的成功靠团队,而不仅是某一个人!项目所需要的知识体系,是由整个团队成员的知识体系总和决定。其实优秀的项目多数都是项目组成员知识能力差异互补,形成的是一个完整圆满的团队。如果项目中仅有一个或者两个“牛人”来支撑,其他组员不能快速学习提升,必然会因为“木桶短板”,导致项目出问题。
另一个困惑很多人的问题是对业务知识的掌握。几乎所有的招聘单位都是要求既要有IT技术知识,开发经验,又要有相关行业背景或者行业软件开发经验才能胜任某一行业IT项目的项目经理。其实造成这样的现状,企业也是被逼出来的。国内的多数软件开发方都比较弱势,为了把项目做好需要做很多本该甲方做的事情。相比而言,懂业务知识的项目经理跟客户沟通更方便,更容易理解客户需求,对推动项目进展有很大的促进作用。但有两个问题需要思考:
1) 项目经理掌握多少业务知识才算够?
2) 有经验,或者某些顶着“专家”头衔的甲方业务人员,就真的能提出很好的IT系统需求么?
诺贝尔经济学奖得主西蒙教授的研究结果表明:“对于一个有一定基础的人来说,他只要真正肯下功夫,在6个月内就可以掌握任何一门学问。”教育心理学界为感谢西蒙教授的研究成果,故命名为西蒙学习法。可见,掌握一门陌生的学问远远没有想想的那么高难、深奥。
研究结果和事实都表明,有行业背景和相关行业软件的开发经验,对项目需求获取有很好的促进作用,可以作为软件项目经理的充分条件,但不是必要条件,“有一定基础”和“肯下功夫”才是关键。做好业务建模,除了熟悉行业知识,更重要的是精通系统分析设计方法和清晰良好的分析判断能力。
三、IT项目经理应该具备的基本个性特征
有很多人一直都不明白有些人讲起管理头头是道,为什么却做不了管理?前面也已经做了分析,学习PMBOK拿了PMP不一定就具备项目管理的能力,每个人的实际能力跟个人天赋有很大关系。对一个项目经理来说,究竟该具备什么样的特质和天赋?笔者概括为四力一度。
1、学习力
二十一世纪,最重要的不是学历,也不是能力,而是学习力!
学习力包括三点:1、喜欢学习;2、快速学习;3、持续学习!这三点缺一不可。
干IT行业注定比其他行业更累,就是因为不断有新的技术、新的思想、新的工具在产生,并且项目经理注定要带各种项目,面对很多行业,没有很好的学习力不可能适应这个行业,更不可能干好。
对很多IT项目经理来说,最可怕的就是“终于由程序员熬成了项目经理”这种想法。国内不少由开发人员晋升上来的项目经理,就是倒在了这条路上!职位的晋升本来是好事,但把一个人安排到不合适的岗位上,真的有可能毁掉一个人。受3000多年传统“官本位”思想的影响,很多国人想做管理,“官”“管”直接挂了钩,在IT行业也不例外。
在很多开发人员眼里,项目经理就是一个指挥指挥,聊聊天,说说话就行的职位,貌似根本不用再学习。有些开发人员就是按照自己的观察理解来干这个工作,放弃了学习,每天忙于项目事务,一些简单的项目基于原有的项目经验,真的有可能会带成功,但遇到复杂的项目,就会发现力不从心,捉襟见肘。
IT项目经理,不仅要学习当下项目需要用到的业务知识、技术知识,掌握新的工具等等,更要不断学习巩固项目管理知识、软件工程知识,因为这些知识体系都在不断的发展充实。而管理学,人类几千年文明史,从未停止过进步。PMBOK现有的5大过程,9大知识领域,没有持续的学习、经验积累、实践总结,绝不可能很好掌握。胸有“万卷诗书”,才可能轻松面对项目中“千奇百怪”复杂的局面!
2、沟通力
沟通管理在PMBOK中做为9大知识领域之一奉献给大家,足见沟通在项目管理中的重要性。沟通力主要体现在两点:1、顺畅良好的沟通;2、适当的沟通力度。
首先要澄清一个误区:沟通能力需要很好的表达能力,包括语言表达、文字表达和肢体表达等,但表达能力不等于沟通能力。细心、耐心,广博的学识、良好的倾听对沟通都非常重要。很多有丰富沟通经验的管理人士强调倾听的重要性,是因为太多人都“好为人师”,喜欢讲,不喜欢听。沟通是个双向的事情,每次沟通一定要明确肯定对方的表达,给予准确答复,同时也要得到对方的明确答复,确认对方真正理解了你的意思。
干系人识别、分析、分类是项目经理制定沟通管理计划首先要做的事情,但更复杂也最能体现项目管理艺术的,就是项目经理要能清晰判断如下内容并付诸实施:
1)在什么时机(到了项目哪个阶段,发生了什么事件);
2)跟哪些人(用户、客户、客户领导、组员、公司领导、销售、监理公司);
3)通过什么方式(会议、当面公谈或私谈、电话、电子邮件、别人转达);
4)在适当的时间(立刻、周几、上午、下午、下班后、几点几分);
5)什么地点(会议室、办公室、茶餐厅……);
6)说什么(长篇大论、简明扼要,这种度需要自己把握)。
每次沟通,如果不能解决问题,就可能产生更大的新问题。以上任何一个环节出了差错,都可能会造成一次事故,给项目带来很大风险。
沟通在项目中是如此重要,顺畅良好的沟通需要项目经理不断观察,学习总结。普遍的观点认为成功的项目经理80%的时间都会运用在沟通上。有些能力很强的项目经理,或是因为心情不佳,或是因为积极性不高,偷懒,侥幸等等心态作怪,在该沟通的时候未进行沟通,致使项目问题堆堆,最终导致项目失败,这是非常可惜可悲的事情。充分准备是良好沟通的必要保证。
沟通是贯穿整个项目生命周期的任务,项目经理要为整个项目创造良好的沟通交流氛围,并把控好沟通的力度:既要保证每次沟通有实际效果,又要保证沟通的周期、时间、时机。
3、决策力
良好决策是成功管理的必须前提,任何管理者都必须具有良好的决策力,项目经理也不例外。良好决策必是基于对现状的清晰认识,因此,首先对项目整体情况的跟踪和检查是项目经理一定要做好的事情,其次就是要求项目经理必须具备良好的分析判断能力。
成熟的方法是项目经理有清晰思路的保证,也是做好分析判断的基础。对分析判断,软件工程和项目管理知识体系提供了很多实用的方法和工具,如软件工程中常用的流程图,质量管理中有名的戴明环(PDCA)、帕累托图、鱼刺图,深刻理解了这些工具的概念、使用方法,理解了其核心思想,我们在面对复杂问题时,就会有很好的分析方法,获得判断依据。
分析判断能力有先天因素的影响,但更重要的是后天的学习和思考。即使是发散型思维,经过学习和训练,也可以形成很好的逻辑判断能力;习惯逻辑思考的人,通过头脑风暴、联想式思考的训练,也可以形成很好的发散思维思考模式。这是对日常事务处理的分析判断。
对于项目经理来说,还有一点就是对干系人行为的分析判断。先天的情商很重要,很多人从小就对别人的行为十分敏感,能比较清晰的判断出对方的情绪、想法以及下一步要采取的行动,也能清晰地知道自己采取的行动能对对方产生好的或者坏的影响,这是情商很高的人。
如果你觉得自己情商不够高,通过学习观察,经验累积,对人的分析判断能力会逐步提高。关于人性的讨论,中华民族是走在世界前列的,“太阳之下,无新鲜事”!通读史书能对人性有很好的了解,还有经典古籍、文学名著,都有助于我们对人性的了解,现代翻译引进的很多西方管理学书籍也都有这方面的论述,《人性的弱点》这本书就很不错。
决策的形成过程有时很漫长,有时只是瞬间,每个项目都会持续一定时期,大的项目甚至会持续很多年,持续不断的正确决策保证项目顺利进行和成功结束。正确的决策一方面依赖于个人天赋,另一反面取决于个人平时的用心程度和用功程度。
4、执行力
任何事情的结果都离不开踏踏实实的执行,我们常听说“千言万语不如一个行动”。但项目管理是如此的实实在在,并且项目管理的典型特征就是时间限制。在有限的时间内通过团队合作来完成项目目标,项目经理没有很好的执行力绝对不行!
在整个项目过程中,会遇到各种各样的问题、麻烦和阻挠,项目经理必须清楚在什么样的时机采取什么样的行动。项目经理是整个项目团队的核心,项目经理的执行力包含两个层面:一是做好自己,把那些需要自己亲力亲为的事情做好;二是推动别人,领导推动项目相关者在相应的时机采取相应的行动,该指挥就上去指挥,需要指导就上去指导,需要协调就择机协调,需要求助上司就及时跟上司汇报。
制定一份优秀的项目计划是一个项目经理能力的体现,将计划按预期逐一落实更是必须具备的能力。项目成功是项目经理的唯一目标,所有的行动都要为此服务!时刻牢记这个目标,采取所有正确的行动来实现这个目标,不要懈怠。
没有一个项目会毫无阻力、没有麻烦的结束,如果项目都那样就不需要项目经理了,项目经理的职责就是解决问题。无论多么优秀的项目经理,没有人能把所有问题都解决得完美无缺。做项目管理,你总会遇到新的问题和麻烦,因此项目经理需要不断的学习、思考和总结,不断改进过程,提高个人能力,改善自己的执行力。
五、成熟度
这里的成熟度主要指个人修养,或者说人格的成熟度。这是一个较大的话题,写几本书未必能描述详尽,但也足以说明个人修养绝非一日之功。个人成熟度受个人成长环境、所受教育、个人天赋等多方面影响,但以下三点对一个成功的项目经理有着至关重要的影响,如果这三点不具备,肯定会出大问题。
1、 信仰正确
信仰是每个人都必须面对的。谈到信仰大家多数立刻会想到宗教或哲学派别,在这里不评论宗教或者哲学派别的好坏对错,这是人类一直在探索和争论的永恒话题。这里的信仰,是指每个人自己心目中的生活信条和生活目标。宗教和哲学派别有很大差异,但对“真善美”的追求是人类共识的正确追求。
PMP认证考试时专门加入了职业道德部分,这是无比正确的。一个信仰错误的人,能力越强,破坏力越大。但因为文化差异,PMP考试的职业道德考试也给其他国家,包括中国的考生带来不少困惑和烦恼,作为一个国际性认证,这也是需要改进的一个方面。
一个成功的项目经理,必须有自己清晰的生活信条和生活目标,这些信条务必是由一系列健康乐观,积极向上的处世原则组成。一个有人格缺陷或悲观甚至邪恶信仰的人做项目经理,会给项目团队带来毁灭性打击,甚至会给其他团队或公司带来毁灭性打击。
2、 情绪稳定
是人类,就避免不了喜怒哀乐等心情的变化,有时也会有莫名其妙的忧郁。没有情绪变化的人不会是一个正常的人,但一个任由坏情绪发泄的人绝对是一个不成熟的人,这样的人就好像一个“不定时炸弹”,身边的人不知道他会什么时候“爆炸”。
“炸弹”的说法好像有点夸张,但很多人都领教过“神经质”领导的威力,迫于权势和其他考虑,很多人选择忍受。这颗炸弹威力较轻,会忍受时间长些,一旦遍体鳞伤,肯定会选择离开。但项目经理算不上大领导,项目经理要面对临时组成的团队和各种各样的干系人,这些情况就确定了有太多不稳定因素。如果项目经理不能控制好情绪,这颗“炸弹”的爆炸极有可能成为群爆的“导火索”,最终结局就是遍地尸身。这样的情况已经有无数先例。
项目经理这个团队核心,无疑会比多数团队成员有更大的影响力,项目经理的情绪变化必然会给整个团队带来较大影响。坏情绪未必都会造成坏结果,这需要项目经理审时度势,控制好自己的情绪在合适的时机表现出来。无论如何,不能让情绪造成的“冲动”左右自己的行动,“冲动”是魔鬼,魔鬼从来不会干好事!
心身健康是稳定情绪的关键。心,指思想观念;身,指躯体。积极向上的思想观念会正面影响一个人的一切。大量事实和经验也说明,身体不好的人各种坏情绪会接踵而至。多做充实自己的事,多想快乐的事,多锻炼身体,你一定能心身健康。平衡是一个很重要的项目思维,项目经理首先得能做好工作与生活的平衡。
3、 换位思考
一个不能换位思考的人,一定不是一个成熟的人!
项目经理不可避免要面对很多陌生但很关键的“干系人”,并且要满足各种各样干系人不同的项目需求(而不是个人要求)。换位思考是良好沟通的基础,更是缔造双赢局面的必须。一个不懂得换位思考的项目经理不会懂得理解,更无法做到包容。总是基于自身利益考虑问题必然导致客户严重不满,也必然导致项目失败。
换位思考是一个简单的处世法则,但简单的道理却有很多人无法做到,这也决定了为什么有的人做不了项目经理。古往今来,从孔子的“己所不欲,勿施于人”到《马太福音》的“你们愿意别人怎样待你,你们也要怎样待人”,不同地域、不同种族、不同宗教、不同文化的人们,说着大意相同的话。
在项目的实施过程中,很多情况下项目经理不仅需要做到“换位思考”,还需要“替人办事”,尤其是国内多数软件实施项目,实施方多数处于“弱势”地位。一方面是很多客户在信息化和管理方面的不成熟,不知道该怎么办;另一方面可能是强势的客户知道,但他却不想办。无论哪种情况,很多时候靠协调和合同约束无法完成项目,如果纠缠于责任和法律条款,致使项目时间延迟或者项目失败,最终造成“双输”局面,这绝不是理想的结局。
一个优秀的项目经理,会很好的换位思考,围绕“项目成功”这个最大目标,不会推卸责任,不会纠缠于一些无法界定责任人的小事,会积极地思考、沟通、协调、推动每项任务的顺利进行,哪怕在经济或其他方面吃些“小亏”,处理好项目的每件关键事情,使项目顺利进行。
换位思考,是一个人“智慧”的体现!替人想在前面、做在前面,“智慧”会为你赢得非凡的成功!
四、总结
如果没有充分的知识,一个项目经理无法知道要成功完成项目该“做什么”,“怎么做”;如果没有必备的个人天赋和后天的勤奋努力,也绝无可能成为优秀的项目经理。
项目需要团队合作才能成功,但任何时候,用“求人”不如“求己”来提醒自己,多学习,充实自己,在紧急关头,你会更容易度过难关。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
1.字符串比较,使用“==”还是equals()?
"=="判断两个引用的是不是同一个内存地址(同一个物理对象)。
equals()判断两个字符串的值是否相等。
除非你想判断两个string引用是否同一个对象,否则应该总是使用equals()方法。
如果你了解字符串的驻留(String Interning)则会更好地理解这个问题。
2. 对于敏感信息,为何使用char[]要比String更好?
String是不可变对象,意思是一旦创建,那么整个对象就不可以改变,即使新手觉得String引用变了,实际上只是(指针)引用指向了另一个(新的)对象。
而程序员可以明确地对字符数组进行修改,因此敏感信息(如密码)不容易在其他地方暴露(只要你用完后对char[]置0).
3.在switch语句中使用String作为case条件
从JDK7开始,
Java 6及以前的版本都不支持这样做的
// 只在java 7及更高版本有效!
switch (str.toLowerCase()) { case "a": value = 1; break; case "b": value = 2; break; } |
4.转换String为数字
对于非常大的数字请使用long.代码如下:
int age = Integer.parseInt("10");
long id = Long.parseLong("190"); // 假如值可能很大.
5.如何通过空白符拆分字符串
String的split()方法接收的字符串会被当做正则表达式解析。
"\s"代表空白字符,如空格"",tab制表符"\t",换行"\n",回车"\r".
而编译器在对源代码解析时,也会进行一次字面转码。所以需要"\\s".
String[] strArray = aString.split("\\s+");
6.substring()方法内部是如何处理的?
在JDK6中,substring()方法还是共用原来的char[]数组,通过偏移和长度构造了一个"新"的string.
想要substring取得一个全新创建的对象,使用如下这种方式:
String sub = str.substring(start, end) + "";
当然Java 7中,substring()创建了一个新的char[]数组,而不是共用。想了解更多,请参考:JDK6和JDK7中String的substring()方法及其差异
7.String vs StringBuffer vs StringBuilder
StringBuilder是可变的,因此可以在创建以后修改内部的值。
StringBuffer是同步的,因此是线程安全的,但是效率相对更低。
8.如何重复拼接同一个字符串?
方案一:使用Apache Commons Lang库的StringUtils工具类。
String str = "abcd";
String repeated = StringUtils.repeat(str,3);//abcdabcdabcd
方案二:使用StringBuilder构造,更灵活。
String src = "name"; int len = src.length(); int repeat = 5; StringBuilder builder = new StringBuilder(len * repeat); for(int i=0; i<repeat; i++){ builder.append(src); } String dst = builder.toString(); |
9.如何将String转换成日期?
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String str = "2013-11-07";
Date date = format.parse(str);
System.out.println(format.format(date));//2013-11-07
10.如何统计某个字符出现的次数?
同样使用Apache Commons Lang 库StringUtils类:
int n = StringUtils.countMatches("11112222", "1");
System.out.println(n);
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
刚接触
配置管理的同志,很容易将配置管理等同于SVN,认为SVN系统是一套配置管理系统。这是严重的误解。
配置管理包括: 版本控制,变更控制,基线管理,产品发布管理,权限管理,配置审计,状态报告等。
SVN是一个版本控制系统,除此之外对变更控制,产品发布管理,配置审计都无能为力。类似的 git 也一样。
CC和 CQ才是真正意义上的配置管理系统。所谓管理系统,必须担负起应有的管理功能。
举一个最简单的例子,svn中只有checkout commit update几个动作。对于配置项的状态是没有检入和检出的标记的。因此,如果发生变更控制某个配置项的变更,只能通过权限方式去实现。而CC中则清楚地分开了检入和检出动作。管理员可以要求项目组每天至少检入一次。这种要求在SVN中变得难以实现。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
令我印象深刻而难以忘怀的,是我亲自经历的、亲眼目睹的、道听途说的一个又一个的软件项目,它们有的获得了成功,但更多的是令人沮丧的失败。套用一下大文豪托尔斯泰体:幸福的家庭都是一样的,不幸的家庭却各有各的不幸;幸福的软件项目都是一样的,不幸的软件项目却各有各的不幸;或者说,成功的软件项目都是一样的,失败的项目却各有各的问题。我常常在想,我们的项目开发到底怎么了,进而把它们一个一个的剥开来深入分析,竟然触目惊心。它们有的是需求的问题,有的是客户关系的问题,还有设计的问题、技术的问题、时间管理的问题、人员培养的问题.....但归根到底更多的还是需求的问题。需求分析既是一份体力活儿,更是一份技术活儿,它既是人际交往的艺术,又是逻辑分析与严密思考的产物。正是我们在需求分析过程存在的巨大隐患,最终导致了那么多项目的失败。也许你认为我在危言耸听,好吧,我来举几个典型事例分析分析吧。
我的第一个故事来自大名鼎鼎的东软。我在2005年接一个项目的时候,听说这个项目之前是东软做的。当时东软在做这个项目的时候,整个过程经历了10多次结构性的大变更,局部性的调整更是不计其数。据说某天早上,客户对某个功能不满意,他们不得不对几百处程序进行修改。之后客户对修改的内容还是不满意,又不得不将几百处修改重新改回来。最后这个项目导致的结果是,整个这个项目组的所有成员都离开了东软,并似乎从此不愿涉足
软件开发领域。多么惨痛的教训啊!我常常听到网友抱怨客户总是对需求改来改去,但客户对需求改来改去的真正原因是什么呢?当我们对客户的需求没有真正理解清楚时,我们做出来的东西客户必然不满意。客户只知道他不满意,但怎样才能使他满意呢?他不知道,于是就在一点儿一点儿试,于是这种反复变更就这样发生了。如果我们明白了这一点,深入地去理解客户的业务,进而想到客户的心坎儿上去,最后做出来的东西必然是客户满意的。记住,当客户提出业务变更的时候,我们一定不能被客户牵着走,客户说啥就是啥。我们要从业务角度深入的去分析,他为什么提出变更,提得合不合理,我有没有更合理的方案满足这个需求。当我们提出更加合理的方案时,客户是乐于接受的,变更也变得可控了。
第二个故事来自我自己的项目,一个早期的项目。在这个项目中,客户扔给了我们很多他们目前正在使用的统计报表,要我们按照报表的格式做出来。这些报表都是手工报表,许多格式既不规范,又很难于被计算机实现。这些报表令我耗费了不少脑细胞,直到最终项目失败都没法完成。这件事留给我的深刻教训是,不能客户怎么说软件就怎么做。客户提出的原始需求往往是不考虑技术实现,基于非计算机管理的操作模式提出来的。他们提出的很多需求常常比较理想而不切实际,毕竟人家是非技术的。但我们作为技术人员,需求分析必须实事求是的、基于技术可以实现的角度去考虑。那种“有条件要上,没有条件创造条件也要上”的鲁莽行事,结果必然是悲惨的。所以我们必须要基于技术实现去引导客户的需求。同时,计算机信息化管理就是一次改革,对以往手工管理模式的改革。如果我们上了信息化管理系统,采用的管理模式却依然是过去的手工模式,新系统的优势从何而来呢?因此,我们做需求就应当首先理解现有的管理模式,然后站在信息化管理的角度去审视他们的管理模式是否合理,最后一步一步地去引导他们按照更加合理的方式去操作与管理。
2007年,我参与了一个集团信息化建设的项目。这个项目中的客户是一个庞大的群体,他们分别扮演着各种角色。从机构层次划分,有集团领导、二级机构人员、三级机构人员;从职能角色划分,有高层领导、财务人员、生产管理员、采购人员、销售人员,等等。在这样一个复杂场景中,不同人员对这个项目的需求是各自不同的。非常遗憾的是,我们在进行需求分析的时候没有认真分析清楚所有类型人员的需求。在进行需求调研的时候,总是集团领导带领我们到基层单位,然后基层单位将各方面的人员叫来开大会。这样的大会,各类型的人员七嘴八舌各说各自的需求,还有很多基层人员在大会上因为羞涩根本就没有提出自己的需求。这样经过数次开会,需求调研就草草收场。我们拿着一个不充分的需求分析结果就开始项目开发,最终的结果可想而知。直到项目上线以后,我们才发现许多更加细节的业务需求都没能分析到,系统根本没法运行,不得不宣告失败。一个软件项目的需求调研首先必须要进行角色分析,然后对不同的角色分别进行调研。需求调研的初期需要召开项目动员大会,这是十分必要的。但真正要完成需求分析,应该是一个一个的小会,1~3个业务专家,只讨论某个领域的业务需求,并且很多问题都不是能一蹴而就完成的,我们必须与专家建立联系,反复沟通后完成。需求分析必须遵从的是一定的科学方法,而不是盲目的大上快上。
我的最后一个故事可能典型到几乎每个人都曾经遇到过。我们的项目从需求分析到设计、开发、
测试都十分顺利。但到了项目进行的后期,快到达最后期限时,我们将我们的开发成果提交给客户看,客户却对开发结果不满意,提出了一大堆修改,而且这些修改
工作量还不小。怎么办呢?加班、赶工,测试时间被最大限度压缩。最后项目倒是如期上线了,但大家疲惫不堪,并且上线以后才发现许多的BUG。需求分析不是一蹴而就的,它应当贯穿整个开发周期,不断的分析确认的过程。以上这个事例,如果我们提早将开发成果给客户看,提早解决问题,后面的情况就将不再发生。这就是
敏捷开发倡导的需求反馈。敏捷开发认为,需求分析阶段不可能解决所有的需求问题,因此在设计、开发、测试,直到最终交付客户,这整个过程都应当不停地用开发的成果与客户交流,及时获得反馈。只有这样才能及时纠正需求理解的偏差,保证项目的成功。
以上的故事各有各自的不幸,各自都在不同的开发环节出现了问题。但经过深入的分析,各自的问题最终都归结为需求分析出现了问题。为了使我们今后的软件项目不会重蹈覆辙,似乎真的有必要讨论一下我们应该怎样做需求分析。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
之前写过一篇
Appium for windows的
文章,因为是09年的T400,启动
Android模拟器的时候死机三次,那就公司申请台Macbook air吧,15寸的Macbook Pro实在太重了,也就Mac才能真正发挥Appium的功能,支持Android和iOS。好了,废话不多,开始。
1. 爬墙
因为后续安装过程中可能会碰到墙的问题,所以首先得解决爬墙的问题。
我的方便,公司提供代理。
guowenxie-macbookair:~ guowenxie$ java -version
java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)
3. git
guowenxie-macbookair:~ guowenxie$ git --version
git version 1.8.5.2 (Apple Git-48)
4. ruby
guowenxie-macbookair:~ guowenxie$ ruby -v
ruby 2.0.0p451 (2014-02-24 revision 45167) [universal.x86_64-darwin13]
5. brew
guowenxie-macbookair:~ guowenxie$ brew -v
Homebrew 0.9.5
这边提下brew的安装,brew是Mac OS不可或缺的套件管理器
执行下面命令
ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"
6. node
有了brew安装node就方便了
brew install node
7. npm
guowenxie-macbookair:~ guowenxie$ npm -v
2.0.0-alpha-5
8. Appium
现在可以开始安装Appium
guowenxie-macbookair:~ guowenxie$ appium -v
1.2.0
9. wd
npm install wd
10. Xcode和Android SDK
这个不说了
11. 检查环境
Appium提供了一个doctor,运行appium-doctor
guowenxie-macbookair:~ guowenxie$ appium-doctor Running iOS Checks Xcode is installed at /Applications/Xcode.app/Contents/Developer Xcode Command Line Tools are NOT installed: Error: Command failed: No receipt for 'com.apple.pkg.CLTools_Executables' found at '/'. Fix it (y/n) y Press any key to continue: Xcode Command Line Tools are installed. DevToolsSecurity is enabled. The Authorization DB is set up properly. Node binary found at /usr/local/bin/node iOS Checks were successful. Running Android Checks ANDROID_HOME is set but does not exist on the file system at "Users/guowenxie/Documents/adt-bundle_mac-x86_64-20140702/sdk" Appium-Doctor detected problems. Please fix and rerun Appium-Doctor. |
这里可以看到我Xcode Command Line Tools没有安装,这个方便,Fix it 的时候输入Y,就能自动导向安装了。
另一个是ANDROID_HOME的环境变量没配置好,那么我们要配置下。
12. bash_profile文件
Mac 默认是没有这个文件的,我们自己建一个
touch .bash_profile
vi .bash_profile
打开bash_profile文件配置ANDROID_HOME和JAVA_HOME
export ANDROID_HOME="/Users/guowenxie/Documents/adt-bundle-mac-x86_64-20140702/sdk"
export JAVA_HOME=$(/usr/libexec/java_home)
source .bash_profile
好了,再次运行appium-doctor
guowenxie-macbookair:~ guowenxie$ appium-doctor Running iOS Checks Xcode is installed at /Applications/Xcode.app/Contents/Developer Xcode Command Line Tools are installed. DevToolsSecurity is enabled. The Authorization DB is set up properly. Node binary found at /usr/local/bin/node iOS Checks were successful. Running Android Checks ANDROID_HOME is set to "/Users/guowenxie/Documents/adt-bundle-mac-x86_64-20140702/sdk" JAVA_HOME is set to "/usr/libexec/java_home." ADB exists at /Users/guowenxie/Documents/adt-bundle-mac-x86_64-20140702/sdk/platform-tools/adb Android exists at /Users/guowenxie/Documents/adt-bundle-mac-x86_64-20140702/sdk/tools/android Emulator exists at /Users/guowenxie/Documents/adt-bundle-mac-x86_64-20140702/sdk/tools/emulator Android Checks were successful. All Checks were successful |
到此,环境基本准备好了。
最后,如果不想通过命令行安装Appium,也可以安装dmg
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters