thinkphp5 (最棒的php开源框架)
tp5的唯一可访问目录是public,即项目根目录:
http://localhost/tp5/public/
开发规范:
类库、函数文件统一以.php为后缀
类(命名和路径)和命名空间保持一致
类文件采用驼峰法命名,首字母大写(类文件名 = 类名),其它文件用小写+下划线
方法和属性,采用驼峰法命名,首字母小写
常量,大写字母+下划线
配置参数,小写字母+下划线
应用类库的根命名空间统一为app,不建议更改
如果你的应用下面只有一个模块,那么这个模块的子目录可以省略,并设置参数:
'app_multi_module' => false,
控制器类比较灵活,可以无需继承任何基础类库
模型中,只有进行实际的数据库查询操作的时候,才会进行数据库的连接
可以把模型层进行多层设计,分为逻辑层/服务层/事件层
入口文件代码:
// 定义项目路径
define('APP_PATH', __DIR__ . '/../application/');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';
start.php引导文件会执行:
加载系统常量定义;
加载环境变量定义文件;
注册自动加载机制;
注册错误和异常处理机制;
加载惯例配置文件;
执行应用;
统一使用return返回数据,而不是echo输出,如非必要,请不要使用exit或者die中断执行
URL是不区分大小写的
http://localhost/index.php/Index/Blog/read
上面URL地址全部改为小写,也是可以的!
怎么访问有大小写的控制器: 采用下划线
http://localhost/index.php/Index/blog_test/read
2.如果希望区分大小写: 修改配置
'url_convert' => false,
隐藏index.php:
1、httpd.conf: 加载mod_rewrite.so模块
2、AllowOverride None 将None改为 All
3、在应用入口文件同级目录添加.htaccess文件,内容如下:
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>
common模块是一个特殊的模块, 默认是禁止直接访问的, 一般用于放置一些公共的类库用于其他模块的继承
模块的命名空间:
app\模块名\controller\控制器名
例如, app\index\controller\Blog
修改app为其它名称: 修改配置
'app_namespace' => 'application',
如果只有一个模块(且只有一个控制器): 直接绑定
define('BIND_MODULE','index');//只有一个模块index
define('BIND_MODULE','index/index');//且只有一个控制器index
访问时, http://localhost/index.php/read 就可以了
如果只有一个模块, 则可以简化目录结构:
修改配置
'app_multi_module' => false,
调整目录
同时, 访问地址和命名空间都可以把模块省略了
trait实现代码复用:
在TP5中, 这么用: (如果是php5.4以上的版本, load_trait可以省略)
控制器输出: 定义输出的格式 'default_return_type'=>'json',
, 直接return(不用echo)
$data = ['name'=>'thinkphp','url'=>'thinkphp.cn'];
return ['data'=>$data,'code'=>1,'message'=>'操作完成'];
也可以用函数 json、view、xml、jsonp 指定输出的数据类型,
return json(['data'=>$data,'code'=>1,'message'=>'操作完成']);
修改配置文件所在目录:
define('CONF_PATH', __DIR__.'/../config/');
扩展配置: 在应用或模块配置目录下面增加extra子目录, 那么这个目录里的所有配置参数会自动加载, 和其它配置进行合并。
自动读取的配置文件都是二级配置参数, 一级配置名称就是扩展配置的文件名。
比如, extra/aaa.php内容如下:
<?php
return [
'abc'=>'hello',
];
那么应该这样读取:
echo Config::get("aaa.abc"); //输出"hello"
配置参数名不区分大小写, 建议全部使用小写。
还可以使用二维数组来配置更多的信息,
读取-->
echo Config::get('user.type');
设置-->
Config::set([
'type' => 'file',
'prefix' => 'think'
],'cache');
修改配置格式: define('CONF_EXT', '.ini');
支持的又, .ini、.xml、.json 和 .php
例如,
手动导入配置:
Config::parse(APP_PATH.'my_config.xml','xml');//第二个参数可以省略
或
$config = 'var1=val
var2=val';
Config::parse($config,'ini');//第二个参数不能省略
判断是否存在某个配置:
Config::has('配置参数2');
或
config("?配置参数2");
动态配置参数:
config('配置参数','配置值');
或
config([
'配置参数1'=>'配置值',
'配置参数2'=>'配置值'
]);
配置参数作用域: 就好比命名空间, 这样就可以定义相同名称的参数了
Config::set('user_type',1,'user'); //此参数纳入user作用域
环境变量配置:
在开发过程中, 在应用根目录下面的.env来模拟环境变量配置, 采用ini的格式, 例如
app_debug = true
app_trace = true
或(第二种是数组形式)
[database]
username = root
password = 123456
读取环境变量-->
Env::get('database.username');//第二个参数表示: 默认值
可以在应用配置中使用环境变量:
return [
'hostname' => Env::get('hostname','127.0.0.1'),
];
路由
+++++++++++++++++++++++++++++++++++++++++++++++++++
设置路由模式: 混合模式, 最好。
'url_route_on' => true,
'url_route_must'=> false,
对需要定义路由规则的访问地址定义路由规则, 其它的仍然按照第一种普通模式的PATH_INFO模式访问URL。
路由定义:
use think\Route;
Route::rule('new/:id','index/News/read');//第三个参数指定请求类型, 为空代表任何类型。
请求类型包括: GET/POST/PUT/DELETE/*
简化写法: Route::get('new/:id','News/read');
多个请求类型: Route::rule('new/:id','News/read','GET|POST');
批量注册路由规则:
Route::rule(['new/:id'=>'News/read','blog/:name'=>'Blog/detail']);
支持静态地址: 'my' => 'Member/myinfo',
可选定义: 'blog/:year/[:month]'=>'Blog/archive',
完全匹配: 在路由表达式最后使用$符号, 'new/:cate$'=> 'News/category',
所有路由都采用完全匹配: 配置参数 'route_complete_match' => true,
支持额外参数: 'blog/:id'=>'blog/read?status=1&app_id=5',
批量注册路由规则:
https://www.kancloud.cn/manual/thinkphp5/118031
给路由规则中的动态变量, 设置正则限制:
https://www.kancloud.cn/manual/thinkphp5/118033
路由规则中没有固定的分隔符, 则使用组合变量:
https://www.kancloud.cn/manual/thinkphp5/131398
可以设置一些路由匹配的条件: 用于验证当前的路由规则是否有效
https://www.kancloud.cn/manual/thinkphp5/118034
路由到模块/控制器、重定向地址、控制器、类、闭包函数:
https://www.kancloud.cn/manual/thinkphp5/118037
支持设置RESTFul请求的路由规则:
https://www.kancloud.cn/manual/thinkphp5/118035
为了缩短URL地址, 使用路由别名:
https://www.kancloud.cn/manual/thinkphp5/163984
允许把相同前缀的路由定义进行合并分组:
https://www.kancloud.cn/manual/thinkphp5/118036
在没有匹配到所有的路由规则后执行一条设定的路由, MISS路由:
https://www.kancloud.cn/manual/thinkphp5/151354
可以使用闭包的方式定义一些特殊需求的路由, 而不需要执行控制器的操作方法了:
https://www.kancloud.cn/manual/thinkphp5/118038
使用路由绑定简化URL或者路由规则的定义:
https://www.kancloud.cn/manual/thinkphp5/118040
路由规则和分组支持绑定模型数据:
https://www.kancloud.cn/manual/thinkphp5/208987
支持完整域名、子域名和IP部署的路由和绑定功能:
https://www.kancloud.cn/manual/thinkphp5/118039
当路由定义变化时, URL地址怎么办:
https://www.kancloud.cn/manual/thinkphp5/118041
控制器
+++++++++++++++++++++++++++++++++++++++++++++++++++
需继承任何的基础类, 命名空间默认以app为根命名空间。
修改应用类库命名空间:
'app_namespace' => 'application',
输出转换:
采用return时, 控制器会自动进行数据转换处理。
在ajax请求时, 会自动转换为json。
'default_ajax_return' => 'html',//默认输出类型
当设置输出格式为html时, 不会自动转换。
如果你的控制器类继承了\think\Controller类的话, 可以定义控制器初始化方法_initialize
设置 beforeActionList属性可以指定某个方法为其他方法的前置操作: first、second、three、hello、data都是此类里面的方法
protected $beforeActionList = [
'first',
'second' => ['except'=>'hello'],
'three' => ['only'=>'hello,data'],
];
使用redirect助手函数还可以实现, 记住当前的URL后跳转
redirect('News/category')->remember();
需要跳转到上次记住的URL的时候使用:
redirect()->restore();
空操作:
public function _empty($name)
{
//把所有城市的操作解析到city方法
return $this->showCity($name);
}
空控制器:
<?php
namespace app\index\controller;
use think\Request;
class Error
{
public function index(Request $request)
{
//根据当前控制器名来判断要执行那个城市的操作
$cityName = $request->controller();
return $this->city($cityName);
}
//注意 city方法 本身是 protected 方法
protected function city($name)
{
//和$name这个城市相关的处理
return '当前城市' . $name;
}
}
更改默认的空控制器名:
'empty_controller' => 'MyError',
多级控制器: 支持任意层次级别的控制器, 并且支持路由
namespace app\index\controller\one;
use think\Controller;
class Blog extends Controller
{
public function index()
{
return $this->fetch();
}
}
该控制器类的文件位置为:
application/index/controller/one/Blog.php
分层控制器:
namespace app\index\event;
class Blog
{
public function update($id)
{
return 'update:'.$id;
}
}
//调用:
$event = controller('Blog', 'event');
echo $event->update(5);
//跨模块:
$event = controller('Admin/Blog', 'event');
//直接调用分层控制器类的某个方法:
echo action('Blog/update', ['id' => 5], 'event');
自动定位控制器: 如果使用了多级控制器, 则开启这个, 便于URL访问
'controller_auto_search' => true,
>>https://www.kancloud.cn/manual/thinkphp5/156860
资源控制器: 轻松的创建RESTFul资源控制器
>>https://www.kancloud.cn/manual/thinkphp5/182949
请求
+++++++++++++++++++++++++++++++++++++++++++++++++++
请求信息: $request = Request::instance();
设置或获取请求信息, 更详细>>https://www.kancloud.cn/manual/thinkphp5/158834
检查变量是否设置:
Request::instance()->has('id','get');
Request::instance()->has('name','post');
获取param变量:
// 获取当前请求的name变量
Request::instance()->param('name');
// 获取当前请求的所有变量(经过过滤)
Request::instance()->param();
// 获取当前请求的所有变量(原始数据)
Request::instance()->param(false);
// 获取当前请求的所有变量(包含上传文件)
Request::instance()->param(true);
获取变量:
Request::instance()->get('id');
Request::instance()->get('id');
Request::instance()->put('name');
Request::instance()->request('id');
Request::instance()->server('PHP_SELF');
Request::instance()->session('user_id');
Request::instance()->cookie('user_id');
以上都可以用input助手函数来实现,
input('cookie.user_id');
变量过滤:
配置参数
'default_filter' => 'htmlspecialchars',
或设置过滤方法,
Request::instance()->filter(['strip_tags','htmlspecialchars']),
或添加过滤方法,
Request::instance()->param('username','','strip_tags,strtolower');
获取部分变量:
// 只获取GET请求的id和name变量, get参数可以省略
Request::instance()->only(['id','name'],'get');
排除部分变量:
// 排除GET请求的id和name变量, get参数可以省略
Request::instance()->except(['id','name'],'get');
变量修饰符:
input('post.name/s');
Request::instance()->get('id/d');
更改变量:
Request::instance()->get(['id'=>10]);
注意, 尽量避免直接修改$_GET、$_POST数据, 也不能直接修改param变量。
请求类型: 取消了用于判断请求类型的系统常量(如IS_GET, IS_POST等), 统一采用 think\Request类 处理请求类型
Request::instance()->isGet();
其它方法如下,
isPost,isPut,isDelete,isAjax,isPjax、isMobile、isHead、isPatch、isCli、isCgi
请求类型伪装:
1.在form表单里提交_method变量
<input type="hidden" name="_method" value="PUT" >
2.配置参数: 表单请求类型伪装变量
'var_method' => '_m',
3.可以对请求进行ajax伪装
http://localhost/index?_ajax=1
HTTP头信息:
$info = Request::instance()->header();
echo $info['accept'];
或直接获取,
$agent = Request::instance()->header('user-agent');
请求头的名称不区分大小写。
伪静态: 配置参数
'url_html_suffix' => 'html|shtml|xml',
方法注入:
1.注入
Request::hook('user','getUserInfo');
2.函数:
function getUserInfo(Request $request, $userId){
// 根据$userId获取用户信息
return $info;
}
3.在控制器中调用:
public function index(){
$info = Request::instance()->user($userId);
}
属性注入:
1.注入
Request::instance()->user = new User;
2.获取
Request::instance()->user;
参数绑定:
把URL地址(或者路由地址)中的变量作为操作方法的参数直接传入
假设定义了如下控制器,
namespace app\index\Controller;
class Blog {
public function archive($year='2016',$month='01'){
return 'year='.$year.'&month='.$month;
}
}
1.按名称绑定
http://serverName/index.php/index/blog/archive/year/2016/month/06
//必须指定year、month参数的名称, 顺序随意
2.按顺序绑定
'url_param_type' => 1,//先修改配置参数为1
然后,
http://serverName/index.php/index/blog/archive/2016/06
依赖注入: 针对访问控制器进行依赖注入
1.架构方法注入
namespace app\index\controller;
use think\Request;
class Index{
protected $request;
public function __construct(Request $request) {
$this->request = $request;
}
public function hello() {
return 'Hello,' . $this->request->param('name') . '!';
}
}
2.操作方法注入
namespace app\index\controller;
use think\Request;
class Index{
public function hello(Request $request){
return 'Hello,' . $request->param('name') . '!';
}
}
请求缓存: 支持对请求地址设置缓存访问, 并设置有效期(只针对GET有效)
1.路由
Route::get('new/:id','News/read',[
'cache' => [ 'cache_flag',3600]
]);
2.动态设置
Request::instance()->cache('blog/:id',3600);
Request::instance()->cache('__URL__',600);//以当期URL地址作为缓存标识
Request::instance()->cache('[html]',600);//对html后缀的请求进行缓存
3.自动判断缓存: 配置参数
'request_cache' => true,
'request_cache_expire' => 3600,
'request_cache_except' => [ //设置排除规则
'/blog/index',
'/user/member'
],
数据库
+++++++++++++++++++++++++++++++++++++++++++++++++++
连接数据库:
1.配置参数: database.php
return [
'type' => 'mysql',
'dsn' => '',
'hostname' => '127.0.0.1',
'database' => 'thinkphp',
'username' => 'root',
'password' => '',
'hostport' => '',
'params' => [],
'charset' => 'utf8',
'prefix' => 'think_',
'debug' => false,
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0,
// 数据库读写是否分离 主从式有效
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
// 是否严格检查字段是否存在
'fields_strict' => true,
];
2.每个模块可以单独配置: 相同参数无需重复配置
return [
'hostname' => '192.168.1.100',
'database' => 'admin',
];
3.配置参数: 断线重连
'break_reconnect' => true,
4.在方法中动态定义连接信息
Db::connect('mysql://root:1234@127.0.0.1:3306/thinkphp#utf8');
或,
Db::connect('db_config1');//db_config1是配置参数
5.在模型中定义连接信息
namespace app\index\model;
use think\Model;
class User extends Model{
protected $connection = 'mysql://root:1234@127.0.0.1:3306/thinkphp#utf8';
//或
//protected $connection = 'db_config1';
}
基本使用:
Db::query('select * from think_user where id=?',[8]);
Db::execute('insert into think_user (id, name) values (?, ?)',[8,'thinkphp']);
Db::query('select * from think_user where id=:id',['id'=>8]);
Db::connect($config)->query('select * from think_user where id=:id',['id'=>8]);
CURD操作事件:
仅支持find、select、insert、update和delete方法。
Query::event('after_insert','callback');
或,
Query::event('before_select',function($options,$query){
return $result;
});
事务操作:
Db::transaction(function(){
Db::table('think_user')->find(1);
Db::table('think_user')->delete(1);
});
或手动控制事务,
// 启动事务
Db::startTrans();
try{
Db::table('think_user')->find(1);
Db::table('think_user')->delete(1);
// 提交事务
Db::commit();
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
}
监听SQL:
Db::listen(function($sql, $time, $explain){
// 记录SQL
echo $sql. ' ['.$time.'s]';
// 查看性能分析结果
dump($explain);
});
调用存储过程:
$result = Db::query('call sp_query(?)',[8]);
数据集:
1.使用
$users = Db::name('user')->select();
if($users->isEmpty()){ //不能用empty判断
echo '数据集为空';
}
2. 返回的数据集对象是think\Collection, 包含这些方法
分布式数据库:
https://www.kancloud.cn/manual/thinkphp5/118061
查询构造器(链式操作):
https://www.kancloud.cn/manual/thinkphp5/135175
查询数据:
1.value: 返回某个字段的值
Db::table('think_user')->where('id',1)->value('name');
2.column: 返回某一列的值
Db::table('think_user')->where('status',1)->column('name','id');
3.分批处理数据集
Db::table('think_user')->chunk(100, function($users) {
foreach ($users as $user) {
//..
}
});
4.查询json字段
Db::table('think_user')->where('info$.email','tp@qq.com')->find();
添加数据:
1.添加一条
$data = ['foo' => 'bar', 'bar' => 'foo'];
Db::name('user')->insert($data);
2.返回自增主键
$userId = Db::name('user')->getLastInsID();
或,
Db::name('user')->insertGetId($data);
3.添加多条
$data = [
['foo' => 'bar', 'bar' => 'foo'],
['foo' => 'bar1', 'bar' => 'foo1'],
['foo' => 'bar2', 'bar' => 'foo2']
];
Db::name('user')->insertAll($data);//返回添加成功的条数
更新数据:
1.有主键时
Db::table('think_user')
->update(['name' => 'thinkphp','id'=>1]);
2.延迟更新: 第三个参数
Db::table('think_user')->where('id', 1)->setInc('score', 1, 10);
3. 要更新的数据需要使用SQL函数或者其它字段
Db::table('think_user')
->where('id', 1)
->update([
'login_time' => ['exp','now()'],
'login_times' => ['exp','login_times+1'],
]);
删除数据:
1.根据主键
Db::table('think_user')->delete(1);
或
Db::table('think_user')->delete([1,2,3]);
2.条件删除
Db::table('think_user')->where('id','<',10)->delete();
查询方法:
1.AND条件
Db::table('think_user')
->where('name','like','%thinkphp')
->where('status',1)
->find();
2.OR条件
Db::table('think_user')
->where('name','like','%thinkphp')
->whereOr('title','like','%thinkphp')
->find();
3.获取表信息
Db::getTableInfo('think_user', 'fields');
//fields 所有字段、type 所有字段的类型、pk 表主键
//也可省略第二个参数, 表示获取表的所有信息
查询表达式:
统计查询:
时间查询:
https://www.kancloud.cn/manual/thinkphp5/165789
只返回sql语句:
1. fetchSql
$subQuery = Db::table('think_user')
->field('id,name')
->where('id','>',10)
->fetchSql(true)
->select();
2. buildSql
$subQuery = Db::table('think_user')
->field('id,name')
->where('id','>',10)
->buildSql();
3. select(false)
$subQuery = Db::table('think_user')
->field('id,name')
->where('id','>',10)
->select(false);
子查询:
1. 在上面代码的基础上...
Db::table($subQuery.' a')
->where('a.name','like','thinkphp')
->order('id','desc')
->select();
生成的SQL语句为:
SELECT * FROM ( SELECT `id`,`name` FROM `think_user` WHERE `id` > 10 ) a WHERE a.name LIKE 'thinkphp' ORDER BY `id` desc
2. 使用闭包...
Db::table('think_user')
->where('id','IN',function($query){
$query->table('think_profile')->where('status',1)->field('id');
})
->select();
原生操作: 最好使用参数绑定, 安全!
Db::query("select * from think_user where id=? AND status=?",[8,1]);
Db::execute("update think_user set name=:name where
status=:status",['name'=>'thinkphp','status'=>1]);
模型
+++++++++++++++++++++++++++++++++++++++++++++++++++
;
thinkphp5 (最棒的php开源框架)的更多相关文章
- 开源框架:SDWebImage
http://blog.csdn.net/uxyheaven/article/details/7909373 SDWebImage是我搞iOS以来少数佩服的框架,膜拜一下作者.真的写的非常棒! 这套开 ...
- thinkphp5升级版开源框架tpframe v2.1发布
免费开源框架tpframe是一款以thinkphp5为驱动,在此基础上进行进一步的完善与改进的框架,保持了ThinkPHP5原有的所有特性,优化核心,减少依赖,为个人或企业建站提供高效.快速解决的方案 ...
- Pyhton开源框架(加强版)
info:Djangourl:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC)风格的 ...
- Python开源框架
info:更多Django信息url:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC) ...
- 开源框架】Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发
[原][开源框架]Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发,欢迎各位... 时间 2015-01-05 10:08:18 我是程序猿,我为自己代言 原文 http: ...
- SunSonic 3.0 ORM开源框架的学习
SubSonic 3.0简介 接触到SubSonic3.0 ORM框架是看了AllEmpty大神的从零开始编写自己的C#框架(链接在此)系列的随笔接触到的,本文章学习内容源于AllEmpty大神. S ...
- 30 个很棒的 PHP 开源 CMS 内容管理系统
本文汇集了30个优秀的开源CMS建站系统,采用PHP开发.以下列表不分先后顺序. 1. AdaptCMS AdaptCMS Lite 是一个开源的CMS系统,主要特点是易用,而且可以轻松和其他系统接驳 ...
- 开源框架Caliburn.Micro
Caliburn.Micro学习笔记----引导类和命名匹配规则 用了几天时间看了一下开源框架Caliburn.Micro 这是他源码的地址http://caliburnmicro.codeple ...
- 值得学习的C/C++开源框架(转)
值得学习的C语言开源项目 - 1. Webbench Webbench是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的 ...
随机推荐
- NOIP2016模拟赛三 Problem C: 不虚就是要AK
题目大意 给定一棵带有边权的树, 问你在树上随机选两个点, 它们最短路径上的边权之和为\(4\)的倍数的概率为多少. Solution 树分治. 没什么好讲的. #include <cstdio ...
- 发现一个直播录制工具you-get
地址:https://github.com/soimort/you-get 截至到今天,支持的平台如下: Site URL Videos? Images? Audios? YouTube https: ...
- CBIntrospector俗称:内部检查工具
Download View Introspector (CBIntrospector)内部检查工具是IOS和IOS模拟器的小工具集,帮助在调试的UIKit类的用户界面,它尤其有用于动态UI布局创建 ...
- CoreData: 如何预载/导入已有的数据
原文地址:CoreData: 如何预载/导入已有的数据作者:出其东门 在系列教程一中,我们为对象建立了可视化数据模型,运行了快速肮脏测试并勾在一个表视图(table view)中来显示.而在这个教程, ...
- ASIHTTPRequest, request sent twice
´ve just started using ASIHTTPRequest for iOs and I have a small issue with it. All requests are sen ...
- linux查看端口状态相关命令
netstat netstat 命令应用是比较频繁的,比如查看端口占用啦,查看端口进程啦,这些时候都是有必要的. netstat命令各个参数说明如下: -t : 指明显示TCP端口 -u : 指明显示 ...
- java项目热加载工具jrebel
flask有热加载的功能,修为代码后,自动生效. java项目也有类似的功能,不过需要使用收费的插件jrebel 提供一个免费的注册服务器:http://139.199.89.239:1008/884 ...
- 2016.11.10 Could not get JDBC Connection; nested exception is java.sql.SQLException: No suitable driver
运行项目rds_web时,出现错误提示:Could not get JDBC Connection; nested exception is java.sql.SQLException: No sui ...
- 白盒测试中如何实现真正意义上并发测试(Java)
在这个话题开始之前,首先我们来弄清楚为什么要做并发测试? 一般并发测试,是指模拟并发访问,测试多用户并发访问同一个应用.模块.数据时是否产生隐藏的并发问题,如内存泄漏.线程锁.资源争用问题. 站在性能 ...
- NSTimer使用不当引发的内存泄漏问题
NSTimer可以用来执行一些定时任务,比较常用的方法就是: + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTar ...