EasyUI学习笔记第四天

要解决的问题

  • 表格编辑时下拉

  • 表单编辑时下拉

  • 查询条件下拉

  • 下拉的数据都来自于服务器

  • 下拉的数据都来自于本地

  • 表单加载时无法自动获取那些下拉框值

解决问题的办法

combobox组件

combobox组件属性

加载表单之前进行下拉框的初始化而不是之后再进行初始化

表单加载之后再进行下拉框的初始化,这时的下拉框是无值的

代码

combobox远程数据

1
2
3
4
5
$("#query_qxyId").combobox({
url: urlPrefix + '/qxy/get.do',
valueField:'qxyId',
textField:'mc'
})

combobox加载本地数据

1
2
3
4
5
6
7
8
9
10
11
12
13
<input class="easyui-combobox" data-options="
valueField: 'label',
textField: 'value',
data: [{
label: 'java',
value: 'Java'
},{
label: 'perl',
value: 'Perl'
},{
label: 'ruby',
value: 'Ruby'
}]" />

表格编辑时下拉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
field : 'qxyId',
title : '权限域',
width : 100,
align : 'left',
editor : {
type : 'combobox',
options : {
required : false,
valueField: 'qxyId',
textField:'mc',
method:'get',
url: urlPrefix + '/qxy/get.do',
required:true
}
}

查询条件下来

1
2
3
4
5
6
7
8
9
10
11
function getQueryCondition() {
// 获取输入框的值只能通过name而不是id
var query_qxyId = $("input[name='query_qxyId']").val()
console.log("query_qxyId -------" + query_qxyId)
var query_ptmc = $('#query_ptmc').val()
var queryCondition = {}
queryCondition.qxyId = query_qxyId
queryCondition.ptmc = query_ptmc
console.log(queryCondition)
return queryCondition
}

windows 下eclipse的配置

更改文件编码为UTF-8(java,jsp,其他文件)

1
2
3
window --> preference --> general-->workspace (other file)
window --> preference --> general-->content types(java)
window --> preference --> web --> (html,css,jsp)

配置自己安装的JDK Maven Tomcat

1
2
3
4
5
6
installed jre(jdk)
maven --> installations
自定义配置 maven --> user settings
##tomcat 和eclipse关联
server -- > runtime enviroments

更改Eclipse下Tomcat的部署目录

关联好tomcat后,打开servers视图,新建一个服务器,不要点击next直接点finish。

如果点next会提示你直接发布项目,一旦发布项目,这个服务器的部署目录便无法更改。

项目的默认目录会在 ….\workspace.metadata.plugins\org.eclipse.wst.server.core\

选中服务器,右键open,这样便可以配置tomcat部署目录,一般选择第二个.

eclipse-tomcat部署路径配置

每天练练markdown

学习链接

markdown官网

中文版markdown教程

已有基础知识

“#”代表标题层级

1
2
3
4
5
#
##
###
####
there is a blank between # and title

添加超链接

1
2
3
[]()
[baidu](http://www.baidu.com)
there is no blank between []()

添加图片

1
2
![]()
eg: ![this is a image](../iimages/20160316/test.png)

代码块

1
选中代码,按tab键缩进,若行首四个空格,Markdown 解析器会把它考虑成代码块

高亮显示代码

Markdown高亮显示

列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
无序列表使用星号、加号或是减号作为列表标记:
* Red
* Green
* Blue
等同于:
+ Red
+ Green
+ Blue
也等同于:
- Red
- Green
- Blue
有序列表则使用数字接着一个英文句点:
1. Bird
2. McHale
3. Parish
很重要的一点是,你在列表标记上使用的数字并不会影响输出的 HTML 结果

ubuntu 64位安装DrClient

ubuntu 64位安装DrClient

编译环境:build-essential gcc g++

32位库: lib32z1
(必须先安装32位的运行库,否则程序无法报任何信息)
提示的缺少的库:

{

libSM.so.6 libXi.so.6: libXrender.so.1 libXrandr.so.2

libXcursor.so.1 libXinerama.so.1 libfreetype.so.6 libfontconfig.so.1

libstdc++.so.6

}

实际要安装的库

libsm6:i386 libxi6:i386 libxrender1:i386 libxrandr2:i386

libxcursor1:i386 libxinerama1:i386 libfreetype6:i386 libfontconfig1:i386 libstdc++6:i386

EasyUI学习笔记第三天

要解决的问题

表单式增加,更改和查看详细信息
将表单序列化成json

遇到的问题

  • 弹出表单
  • 新增和更改公用一个表单
  • 编辑表单时自动填充已有字段
  • 表格中未显示的字段仍然能够自动填充到表单
  • 删除更改成功,增加失败(http 415)

    解决问题的方法

通过工具栏按钮弹出dialog

用dialog组件包裹form可为form增加dialog拥有的行为(弹出,关闭)

表单式操作Basic CRUD Application

表单数据填充是根据row的field来加载的

自动填充的原理是row 的field和表单元素中name对应,row中没有的数据是无法加载到表单的

可以设置表格中的字段隐藏,这样表单仍然会加载隐藏的数据

datagrid列属性hidden来控制列的显示和隐藏

增加和(删除,查询,更改)的区别

新增加时,row会全部复制表单字段的值

因为查询出来的数据是有id的,更改和删除时也是根据id来操作的,但是增加时有id一般会出错,

一般的主键都是数据库里自增的,若手动设置id基本会插入失败

所以增加之前必须获得的数据进行处理,删掉id属性

代码

表单序列化

因为是jqeury插件形式的代码,所有jquery对象都可用

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
$.fn.serializeObject = function()
{
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
}
// 一个保存函数
function savePt(){
if(formMethod == undefined){return}
var ptjson = $("#fm").serializeObject()
console.log("保存之后的序列化")
console.log(ptjson)
if(formMethod == "add"){
delete ptjson['ptId']
console.log("删除ptId属性"+ptjson)
}
console.log(url)
$.ajax({
url : url,
type : "POST",
data : JSON.stringify(ptjson),
dataType : "json",
contentType : "application/json",
success : function(data) {
$('#dlg').dialog('close')
alert("数据提交成功")
query();
},
error : function(data){
alert("数据提交失败")
}
})
$('#dg').datagrid('loaded');
$('#dg').datagrid('reload');
}

表单加载和清除

1
2
3
4
5
6
function loadRemote(){
$('#ff').form('load', 'form_data1.json');
}
function clearForm(){
$('#ff').form('clear');
}

为dialog底部添加按钮

1
2
3
4
5
6
7
8
9
10
11
<div id="dlg" class="easyui-dialog"
style="width: 800px; height: 500px; padding: 10px 20px" closed="true"
buttons="#dlg-buttons">
<form></form>
<div id="dlg-buttons" style="display: block">
<a href="#" class="easyui-linkbutton" iconCls="icon-ok"
onclick="savePt()">保存</a> <a href="#" class="easyui-linkbutton"
iconCls="icon-cancel" onclick="javascript:$('#dlg').dialog('close')">取消</a>
</div>
</div>

增加之前删除多余的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
function getFmJsonWithRightFormat(moduleForm){
var fm = $(moduleForm)
var fmJson = fm.serializeObject()
console.log("保存之后的序列化")
console.log(fmJson)
if(formMethod == "add"){
delete fmJson['ptId']
console.log("删除ptId属性"+fmJson)
}
return fmJson
}

EasyUI学习笔记第二天

待解决问题

  • datagrid缓存式增删改问题

    收获

    缓存式编辑是datagrid的一个核心特点

允许用户有一个更改和撤销的机会,而不是频繁地与数据库交互

缓存式编辑的行为核心是编辑状态

正在编辑 editIndex !=undefined

不在编辑状态  editIndex == undefined

增加和(删除,查询,更改)的区别

新增加时,row会全部复制表单字段的值

因为查询出来的数据是有id的,更改和删除时也是根据id来操作的,但是增加时有id一般会出错,

一般的主键都是数据库里自增的,若手动设置id基本会插入失败

所以增加之前必须获得的数据进行处理,删掉id属性

delete obj[‘id’]

代码

Row editing In datagrid 官网demo

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
/**
*
*/
var editIndex;
var editLength;
var submitNum = 0;
//表单操作时,更改和保存表单共用一个保存函数,增加一个formMethod变量来区分
var urlPrefix = 'http://localhost:8080/ACM/manage_page';
//
//模块专属变量
function pagerFilter(data){
if (typeof data.length == 'number' && typeof data.splice == 'function'){ // 判断数据是否是数组
data = {
total: data.length,
rows: data
}
}
var dg = $(this);
var opts = dg.datagrid('options');
var pager = dg.datagrid('getPager');
pager.pagination({
// pageSize: 10,//每页显示的记录条数,默认为10
pageList: [5,10,15,20],//可以设置每页记录条数的列表
// displayMsg: '当前显示 {from} - {to} 条记录 共 {total} 条记录',
beforePageText: '第',//页数文本框前显示的汉字
afterPageText: '页 共 {pages} 页',
displayMsg: '当前显示 {from} - {to} 条记录 共 {total} 条记录',
onSelectPage:function(pageNum, pageSize){
opts.pageNumber = pageNum;
opts.pageSize = pageSize;
pager.pagination('refresh',{
pageNumber:pageNum,
pageSize:pageSize
});
dg.datagrid('loadData',data);
}
});
if (!data.originalRows){
data.originalRows = (data.rows);
}
var start = (opts.pageNumber-1)*parseInt(opts.pageSize);
var end = start + parseInt(opts.pageSize);
data.rows = (data.originalRows.slice(start, end));
return data;
}
function submitToDB(moduleDatagrid,moduleName) {
var dg = $(moduleDatagrid)
if(editIndex != undefined){alert("请先保存更改的内容")
return
}
dg.datagrid('loaded');
if (submitNum > 0) {
var submittedNum
var updateRows = dg.datagrid('getChanges', 'updated');
if (updateRows.length > 0) {
// submitNum += updateRows.length;
subSave(dg,moduleName,"update", updateRows);
alert('成功更新了' + updateRows.length + '行');
submitNum -= updateRows.length;
query(moduleDatagrid,moduleName);
}
var deleteRows = dg.datagrid('getChanges', 'deleted');
if (deleteRows.length > 0) {
// submitNum += deleteRows.length;
subSave(dg,moduleName,"delete", deleteRows);
alert('成功删除了' + deleteRows.length + '行');
submitNum -= deleteRows.length;
query(moduleDatagrid,moduleName);
}
var insertRows = dg.datagrid('getChanges', 'inserted');
// 增加时调用的数据是处理之后的数据,处理代码在各自模块的js文件中,统一用getAddRowsWithRightFormat()来处理数据
if (insertRows.length > 0){
var rightFormatRows = getAddRowsWithRightFormat(moduleDatagrid)
subSave(moduleDatagrid,moduleName,"add", rightFormatRows);
alert('成功增加了' + insertRows.length + '行');
submitNum -= insertRows.length;
query(moduleDatagrid,moduleName);
}
}
}
//删除和更改向后台提交
function subSave(moduleDatagrid,moduleName,method, rows) {
var dg = $(moduleDatagrid)
var msg;
$.each(rows, function(i, o) { // i:遍历的序号 o:当前遍历到的对象
o = rows[i]
var url = urlPrefix + moduleName + method + '.do';
$.ajax({
url : url,
type : "POST",
data : JSON.stringify(o),
success : function(data) {
if (msg) {
$.messager.alert('错误', '操作失败:' + msg, 'error');
dg.datagrid('loaded');
}
},
error:function(data){
alert("操作失败")
},
dataType : "json",
contentType : "application/json"
});
dg.datagrid('acceptChanges');
dg.datagrid('loaded');
dg.datagrid('reload');
});
}
$.fn.serializeObject = function()
{
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
}
//缓存操作添加一条记录
function insertRow(moduleDatagrid){
var dg= $(moduleDatagrid)
if(editIndex != undefined ){
dg.datagrid("endEdit",editIndex)
}
if(editIndex == undefined){
dg.datagrid("insertRow",{
index : 0,
row : {}
})
dg.datagrid("beginEdit",0)
editIndex = 0
}
}
//缓存操作移除行
function removeRows(moduleDatagrid){
var dg = $(moduleDatagrid)
var removeRows = dg.datagrid('getChecked')
if(removeRows.length>0){
$.each(removeRows,function(index,row){
index = dg.datagrid('getRowIndex', row)
dg.datagrid('deleteRow', index)
})
editIndex = undefined;
// 向外部传送移除的行数
submitNum += removeRows.length
}
else{
editIndex = undefined;
}
}
//保存编辑
function saveEditing(moduleDatagrid) {
var dg = $(moduleDatagrid)
if (editIndex != undefined) {
dg.datagrid('endEdit', editIndex);
editIndex = undefined;
dg.datagrid('reload')
}
var updateRows = dg.datagrid('getChanges', 'updated')
var insertRows = dg.datagrid('getChanges', 'inserted')
submitNum += updateRows.length
submitNum += insertRows.length
}
function getChanges() {
if (editIndex == undefined) {
alert(submitNum + '行被改变了!');
} else {
alert("请先保存编辑的行")
}
}
//撤销更改的内容
function reject(moduleDatagrid) {
var dg = $(moduleDatagrid)
dg.datagrid('rejectChanges');
// 撤销之后清空全局信号量
editIndex = undefined;
editLength = 0;
submitNum = 0;
}
function editRow(moduleDatagrid) {
var dg = $(moduleDatagrid)
if (editIndex != undefined)
return;
var row = dg.datagrid('getSelected');
if (row == undefined) {
$.messager.alert('提示', "请先单击选中要编辑的行", 'info');
return;
}
var index = dg.datagrid('getRowIndex', row);
dg.datagrid('beginEdit', index);
var editors = dg.datagrid('getEditors', index);
editIndex = index;
editLength = 1;
}

EasyUI学习笔记第一天

学习背景

前两个星期用springMVC和mybatis写运维配置管理系统的后台,

增删改查全部使用json作为数据交换的标准

现在需要用easyUI来实现前后台的对接

easyui背景知识:

同事用easyui实现了简单的样式和静态页面,我需要用datagrid来渲染后台返回的数据,

后台返回的是具有内嵌对象的json数组

比如:
[{“ptId”:2,”qxyId”:2,”ptmc”:”期货资管云4”,”ywzfzrId”:3,”ywbgId”:4,”qysj”:”2016-03-16”,”zt”:”已启用”,”jcpt”:”阿里云”,”ptdz”:”杭州”,”ptyt”:null,”pttp”:null,”bz”:”备注2”,”qxy”:{“qxyId”:2,”mc”:”经济云”},”zg”:{“ryId”:null,”xm”:”陈磊”,”gw”:null},”bg”:{“ryId”:null,”xm”:”谭俊”,”gw”:null},”ywList”:[{“ywId”:null,”ywmc”:”恒生估值2.0”,”ptId”:2,”bbh”:null,”bz”:null}]}]

需要解决的问题

  • datagrid加载远程数据
  • datagrid 显示内嵌的json数据

解决思路和方法

datagrid 关于数据的属性







































名称 类型 描述 默认值
method string 请求远程数据的方法(method)类型。 post
url string 从远程站点请求数据的 URL。 null
queryParams object 当请求远程数据时,发送的额外参数。

代码实例:

$(‘#dg’).datagrid({
queryParams: {
name: ‘easyui’,
subject: ‘datagrid’
}
});
{}
data array,object 要加载的数据。该属性自版本 1.3.2 起可用。

代码实例:

$(‘#dg’).datagrid({
data: [
{f1:’value11’, f2:’value12’},
{f1:’value21’, f2:’value22’}
]
});
null
loader function 定义如何从远程服务器加载数据。返回 false 则取消该动作。该函数有下列参数:

param:要传递到远程服务器的参数对象。

success(data):当检索数据成功时调用的回调函数。

error():当检索数据失败时调用的回调函数。

json loader

后台接收的类型必须是序列化后的json,而且请求方式必须是post,但是datagrid的queryParams的形式是一个对象,json对象,而不是字符串

不管datagrid选项中有没有queryParams,后面跟{}或者JSON.stringify({})

都是报415错误

queryParams后面跟JSON.stringify({})

queryParams后面跟{}或者无queryParams

解决方法:用ajax请求数据,将请求后的数据作为datagrid的本地数据

1
2
3
4
5
6
7
8
9
10
11
12
13
$.ajax({
type:"post",
url:urlPrefix + '/pt/query.do',
dataType:"json",
contentType:"application/json;charset=UTF-8",
data:JSON.stringify(queryCondition),
success: function(data){
// 执行datagrid
// 其中数据配置为data:data
*****
}
error:function(data){
}

@RequestBody要求必须有参数
EasyUI中文官网文档

js 是如何访问嵌套的json的?下面是在node中实现的

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
shuai@localhost ~ % node
> var a = {}
undefined
> a.name = 'siyongshuai'
'siyongshuai'
> var b = {}
undefined
> b.a = a
{ name: 'siyongshuai' }
> b.a.name
'siyongshuai'
// 后台返回的数据是复杂的数组
var d= [{"ptId":2,"qxyId":2,"ptmc":"期货资管云4","ywzfzrId":3,"ywbgId":4,"qysj":"2016-03-16","zt":"已启用","jcpt":"阿里云","ptdz":"杭州","ptyt":null,"pttp":null,"bz":"备注2","qxy":{"qxyId":2,"mc":"经济云"},"zg":{"ryId":null,"xm":"陈磊","gw":null},"bg":{"ryId":null,"xm":"谭俊","gw":null},"ywList":[{"ywId":null,"ywmc":"恒生估值2.0","ptId":2,"bbh":null,"bz":null}]}]
undefined
> d.zg.xm
// TypeError: Cannot read property 'xm' of undefined
// at repl:1:5
// at REPLServer.defaultEval (repl.js:260:27)
// at bound (domain.js:287:14)
// at REPLServer.runBound [as eval] (domain.js:300:12)
// at REPLServer.<anonymous> (repl.js:429:12)
// at emitOne (events.js:95:20)
// at REPLServer.emit (events.js:182:7)
// at REPLServer.Interface._onLine (readline.js:211:10)
// at REPLServer.Interface._line (readline.js:550:8)
// at REPLServer.Interface._ttyWrite (readline.js:827:14)
// 按照数组的方式访问是可以的
> d[0].zg.xm
'陈磊'
              
> var e ={"ptId":2,"qxyId":2,"ptmc":"期货资管云4","ywzfzrId":3,"ywbgId":4,"qysj":"2016-03-16","zt":"已启用","jcpt":"阿里云","ptdz":"杭州","ptyt":null,"pttp":null,"bz":"备注2","qxy":{"qxyId":2,"mc":"经济云"},"zg":{"ryId":null,"xm":"陈磊","gw":null},"bg":{"ryId":null,"xm":"谭俊","gw":null},"ywList":[{"ywId":null,"ywmc":"恒生估值2.0","ptId":2,"bbh":null,"bz":null}]}
undefined
> e.ptmc
'期货资管云4'
> e.zg.xm
'陈磊'
>

datagrid 操作json的方式,一级属性可通过下面的配置直接访问

1
2
3
4
5
6
7
8
9
10
11
12
{
field : 'ywbgId',
title : '运维备岗',
width : 200,
align : 'center',
editor : {
type : 'validatebox',
options : {
required : false
}
}
}

若把filedfiled换成bg.xm
仍然什么都不显示
正确的解决方案是利用EasyUI,datagrid的formatter属性,根据formatter的参数可以看出它内部仍然是通过数组直接访问的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
field : 'ywbgId',
title : '运维备岗',
width : 200,
align : 'center',
editor : {
type : 'validatebox',
options : {
required : false
}
},
formatter : function(value, row, index) {
if (row.zg) {
return row.zg.xm;
} else {
return value;
}
}
}

贴一下平台管理模块控制层(controller)代码

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
package com.hundsun.acm.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.hundsun.acm.model.Pt;
import com.hundsun.acm.service.impl.PtServiceImpl;
@Controller
@RequestMapping("manage_page")
public class PtController {
@Autowired
private PtServiceImpl ptService;
@RequestMapping(value = "/pt/get.do")
public @ResponseBody List<Pt> get() {
Pt pt = new Pt();
return ptService.getPtByCondition(pt);
}
@RequestMapping(value = "/pt/query.do")
public @ResponseBody List<Pt> getPtByName(@RequestBody Pt condition) {
try {
return ptService.getPtByCondition(condition);
} catch (Exception e) {
System.out.println("查询××××××××××平台信息×××××××××发生异常");
return null;
}
}
@RequestMapping(value = "/pt/update", method = RequestMethod.POST)
public @ResponseBody String updatePt(@RequestBody Pt record) {
try {
int flag = ptService.updateById(record);
if (flag == 1) {
return "success";
} else {
return "error";
}
} catch (Exception e) {
System.out.println("更新××××××××××平台信息×××××××××发生异常");
return null;
}
}
@RequestMapping(value = "/pt/add.do")
public @ResponseBody String addPt(@RequestBody Pt record) {
try {
int flag = this.ptService.add(record);
if (flag == 1) {
return "success";
} else {
return "error";
}
} catch (Exception e) {
System.out.println("增加××××××××××平台信息×××××××××发生异常");
return null;
}
}
@RequestMapping(value = "/pt/delete.do", method = RequestMethod.POST)
public @ResponseBody String deletePtByConditon(@RequestBody Pt record) {
try {
int flag = this.ptService.deleteById(record);
if (flag == 1) {
return "success";
} else {
return "error";
}
} catch (Exception e) {
System.out.println("删除××××××××××平台信息×××××××××发生异常");
return null;
}
}
}

The-listener-supports-no-services

问题描述 实例没有注册到监听里面

The listener supports no services

什么是注册

注册就是将数据库作为一个服务注册到监听程序。
客户端不需要知道数据库名和实例名,只需要知道该数据库对外提供的服务名就可以申请连接到数据库。

这个服务名可能与实例名一样,也有可能不一样。

在数据库服务器启动过程中,数据库服务器会向监听程序注册相应的服务(无论何时启动一个数据库,默认地都有两条信息注册到监听器中:数据库服务器对应的实例和服务)

监听程序所处位置及作用

在数据库服务器和客户端之间有一监听程序(Listener),在监听程序中,会记录相应数据库对应的服务名(一个数据库可能对应有多个服务名),当客户端需要连接数据库时,只需要提供服务名,就可以建立客户端和服务器之间的连接.
Listener监听

没有监听程序会怎样

能不能连接数据库?

如果在ORACLE服务器是在本机安装的,可以通过sqlplus username/passwd 连接

1
2
3
4
5
6
7
8
9
10
11
12
[oracle@oracle11g ~]$ sqlplus system/123456
SQL*Plus: Release 11.2.0.4.0 Production on Tue Aug 23 08:44:01 2016
Copyright (c) 1982, 2013, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL>

无法通过监听连接服务器

1
sqlplus username/passwd@listener

1
2
3
4
5
6
7
8
9
10
11
[oracle@oracle11g ~]$ sqlplus system/123456@orcl
SQL*Plus: Release 11.2.0.4.0 Production on Tue Aug 23 08:44:56 2016
Copyright (c) 1982, 2013, Oracle. All rights reserved.
ERROR:
ORA-12541: TNS:no listener
Enter user-name:

监听服务名和实例名

listener.ora
配置的是监听服务

1
2
3
4
5
6
7
8
9
10
11
12
# listener.ora Network Configuration File: /u01/app/oracle/product/11.2.0/dbhome_1/network/admin/listener.ora
# Generated by Oracle configuration tools.
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.56.2)(PORT = 1521))
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
)
)
ADR_BASE_LISTENER = /u01/app/oracle

tnsnames.ora
里面配置的是监听服务名与实例名的对应关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
find /u01 -name tnsnames.ora
/u01/app/oracle/product/11.2.0/dbhome_1/network/admin/samples/tnsnames.ora
/u01/app/oracle/product/11.2.0/dbhome_1/network/admin/tnsnames.ora
# tnsnames.ora Network Configuration File: /u01/app/oracle/product/11.2.0/dbhome_1/network/admin/tnsnames.ora
# Generated by Oracle configuration tools.
ORCL =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.56.2)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = oracle11g))
)
)
#ORCL是服务名,oracle11g是实例名

主动监听和被动监听

可以使用命令lsnrctl status来查看某服务是静态注册还是动态注册。
实例状态为UNKNOWN值时表明此服务是静态注册的设置。
这时监听器用来表明它不知道关于该实例的任何信息,只有当客户发出连接请求时,它才检查该实例是否存在。
动态监听的状态是READY。

解决办法1

在listener.ora上面添加一行

1
2
3
4
5
6
7
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(GLOBAL_DBNAME = oracle11g)
(SID_NAME = oracle11g)
)
)

解决方法2

先启动监听程序,后启动实例

解决方法3

启动实例后,手动注册
手动注册

参考链接

ORACLE监听之动态监听与静态监听特点

vim删除匹配行

删除包含特定字符的行

1
:g/pattern/d

删除不包含指定字符的行

1
2
3
:v/pattern/d
:g!/pattern/d

删除指定行

:x,.d #从x行删除到当前行;
:.,xd #从当前行删除到x行;
:x,.+3d #从x行删除到当前行后第三行;
:x,.-1d #从x行删除到当前行前一行。