存档2020-06-21

Oracle连接数过多释放机制

Oracle连接数过多释放机制

 sqlplus /nolog 
 打开sqlplus  
  
  
 connect /as sysdba  
 使用具有dba权限得用户登陆oracle  
   
  
 show parameter resource_limit 
 显示资源限定是否开启,value为true是开启,为false是关闭  
 
 alter system set resource_limit=true 
 如果未开启,则使用此命令开启资源限定功能  
  
   
 create profile profileName limit connect_time 60 idle_time 30 
 创建profile文件,profileName任意起,connect_time设置连接超过多少分钟后强制释放,idle_time设置连续不活动的会话超过多少分钟后强制释放  
 
 alter user oracleUser profile profileName 
 将profile文件作用于指定用户 

 

 

从上周起,服务器Oracle数据库出现问题,用不到半天,就会报maxsession(150)的问题,肯定是数据库的会话超过最大数了。

  由于服务器跑的是文件传输应用,占用的请求和会话肯定很大,因此用户数不大就已经让oracle的会话数达到最大值。

  处理方式不外乎两种:扩大oracle最大session数以及清除inactive会话,当然还有,就是从数据库连接池和程序bug上面下手。

从各处收集了一些查看当前会话的语句,记录一下:

 

1.select count(*) from v$session;

  select count(*) from v$process;

  查看当前总会话数和进程数,这两个视图就是跟会话及进程有关的重要视图啦,信息都是从这里面取的。

 

2.查询那些应用的连接数此时是多少

select  b.MACHINE, b.PROGRAM , count(*) from v$process a, v$session b where a.ADDR = b.PADDR and  b.USERNAME is not null   group by  b.MACHINE  , b.PROGRAM order by count(*) desc;

 

3.查询是否有死锁

select * from v$locked_object;

 

如果查询结果为no rows selected,说明数据库中没有死锁。否则说明数据库中存在死锁。

接下来说明一下会话的状态:

 

1.active 处于此状态的会话,表示正在执行,处于活动状态。

 

2.killed 处于此状态的会话,表示出现了错误,正在回滚,当然,也是占用系统资源的。还有一点就是,killed的状态一般会持续较长时间,而且用windows下 的工具pl/sql developer来kill掉,是不管用的,要用命令:alter system kill session ‘sid,serial#’ ;

 

3.inactive 处于此状态的会话表示不是正在执行的,比如select语句已经完成。我一开始以为,只要是inactive状态的会话,就是该杀,为什么不释放呢。其 实,inactive对数据库本身没有什么影响,但是如果程序没有及时commit,那么就会造成占用过多会话。解决inactive的方法最好的就是在 oracle中直接设置超时时间,也是有两种方法,区别暂时还不清楚:

 

1.修改sqlnet.ora文件,新增expire_time=x(单位是分钟)  

我的sqlnet.ora位置在D:/oracle/ora92/network/admin

2.通过ALTER PROFILE DEFAULT LIMIT IDLE_TIME 10; 命令修改,记得重启下oracle。

 

修改ORACLE 中的SESSION和PROCESS

会话sessions和进程pocesses的关系
一个process可以有0个、1个或者多个session,一个session也可以存在若干个process中,并行同样是一个session对应一 个process,主session是coordinator session,每个parallel process同样会对应数据库里一个单独的session。可以从v$px_session和v$session中验证这点。
连接connects,会话sessions和进程pocesses的关系

每个sql login称为一个连接(connection),而每个连接,可以产生一个或多个会话,如果数据库运行在专用服务器方式,一个会话对应一个服务器进程(process),如果数据库运行在共享服务器方式,一个服务器进程可以为多个会话服务。

Oracle的sessions和processes的数量关系是:sessions=1.1 * processes + 5

下面我们用两种方法修改PROCESS的最大值
一、通过Oracle Enterprise Manager Console在图形化管理器中修改
以系统管理员的身份登入,进入界面 数据库的例程 – 配置 – 一般信息 – 所有初始化参数,修改processes的值

二、在SQLPLUS中修改
以DBA权限登录,修改PROCESS的值(SESSION的值会跟着改);创建pfile;重新启动数据库。输入的SQL命令如下,回显信息省略了
SQL> connect sys/sys as sysdba
SQL> alter system set processes=400 scope = spfile;
SQL> create pfile from spfile;
SQL> shutdown immediate;
SQL> startup

Oracle–存储过程中之循环语句

一般循环语句有两种:

1)使用for循环实现

declare
  cursor cur is
   select * from tablename;
   aw_row  tablename%rowtype;
begin
   for raw_row in cur
      loop
      dbms_output.put_line(‘test’);
end loop;
end;

注意:for语句直接帮我们做了游标的打开关闭,以及判断工作;所以比较常用。

2)使用while实现:

declare
    cursor cur is
    select * from iss2_foc_response;
    raw_row iss2_foc_response%rowtype;
begin
    open cur;
    FETCH cur
    into raw_row;
    while cur%found
        loop
          dbms_output.put_line(‘test while’);
          FETCH cur
          into raw_row;
      end loop;
   close cur;
end;

注意:这种写法需要打开关闭游标,根据游标的特点,这两种循环的写法是等效的。游标默认打开是只读游标,如果要在用到游标的时候修改游标中的值,需要在游标定义的时候,加上For update语句。

Linq多表查询

var q1 = from orderitem in q2
                     join pd in _iProductDetailContract.Entities on   orderitem.ProductDetailId equals pd.Id
                     join pm in ProductMainContract.Entities on pd.ProductMainId equals pm.Id
                     join user in UserContract.Entities on pm.BuyerId equals user.Id
                     into orderItemBuyer
                     from user in orderItemBuyer.DefaultIfEmpty()
                     group new { orderitem.Price, orderitem.Num }
                     by new { orderitem.ProductDetailId, orderitem.Name, orderitem.Size, orderitem.Price, pm.AliasName, BuyerName = user.Name }
                     into g
                     orderby g.Sum(p => p.Num) descending
                     select new
                     {
                         ProductDetailId = g.Key.ProductDetailId,
                         Name = g.Key.Name,
                         Size = g.Key.Size,
                         AliasName = g.Key.AliasName,
                         BuyerName = g.Key.BuyerName,
                         Num = g.Sum(p => p.Num),
                         Price = g.Key.Price,
                         TotlePrice = g.Sum(p => p.Num * p.Price)
                     }
                     ;

Lambda和Linq三表连接查询加分组

三表连接查询加分组的方法

方法一:Lambda

方法二:Linq

数据库事例:

效果图:



.NetCore JWT认证

1、创建.net core web api项目:

Create a Web API with ASP.NET Core and Visual Studio

按照上面链接创建项目。

2、添加JWT(Bearer Token)认证

  • 在项目的Startup.cs文件中的ConfigureServices方法添加以下代码添加并配置JWT认证:
            //添加jwt验证:services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options => {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,//是否验证Issuer
            ValidateAudience = true,//是否验证Audience
            ValidateLifetime = true,//是否验证失效时间
            ValidateIssuerSigningKey = true,//是否验证SecurityKey
            ValidAudience = Configuration["audience"],//Audience
            ValidIssuer = Configuration["issuer"],//Issuer,这两项和签发jwt的设置一致
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["SecurityKey"]))//拿到SecurityKey
        };
     });

其中 Configuration[“audience”]、Configuration[“issuer”]、Configuration[“SecurityKey”]为读取项目中appsettings.json文件中的自定义字符串。

appsettings.json文件:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  "SecurityKey": "dd%88*377f6d&f£$£$#$%#$%#$FF33fssDG^!3",
  "issuer": "guetServer",
  "audience": "guetClient"
}
  • 在项目的Startup.cs文件中的Configure方法添加以下代码配置授权:
app.UseAuthentication();//配置授权
  • 签发JWT

首先自定义API连接返回的数据类型在项目的Models文件夹添加RestfulData类,新建类文件,对应命名空间里面定义三个类,代码如下:

    public class RestfulData
    {
        /// <summary>
        /// <![CDATA[错误码]]>
        /// </summary>
        public int code { get; set; }

        /// <summary>
        ///<![CDATA[消息]]>
        /// </summary>
        public string message { get; set; }

        /// <summary>
        /// <![CDATA[相关的链接帮助地址]]>
        /// </summary>
        public string url { get; set; }

    }

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class RestfulData<T> : RestfulData
    {
        /// <summary>
        /// <![CDATA[数据]]>
        /// </summary>
        public virtual T data { get; set; }
    }

    /// <summary>
    /// <![CDATA[返回数组]]>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class RestfulArray<T> : RestfulData<IEnumerable<T>>
    {

    }

在项目中Models文件夹新建TokenObj类,代码如下

    public class TokenObj
    {
        public string token { get; set; }//token内容

        public long expires { get; set; }//过期时间
    }

做好以上准备之后在项目的Controllers文件夹里面新建一个API控制器类,如下图:

命名为OAuthController.cs。

将里面的方法全部删除,添加入以下代码

        private readonly IConfiguration _configuration;
  
        public OAuthController(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        /// <summary>
        /// <![CDATA[获取访问令牌]]>
        /// </summary>
        /// <param name="user"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<RestfulData<TokenObj>> Token(string user, string password)//同步方法
        {
            var result = new RestfulData<TokenObj>();
            try
            {
                if (string.IsNullOrEmpty(user)) throw new ArgumentNullException("user", "用户名不能为空!");
                if (string.IsNullOrEmpty(password)) throw new ArgumentNullException("password", "密码不能为空!");

                //验证数据库用户名和密码
                //var userInfo = await _UserService.CheckUserAndPassword(user,  password);
                var claims = new Claim[]
                {
                    new Claim(ClaimTypes.Name,user),
                    new Claim(ClaimTypes.NameIdentifier,password),
                };

                var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(_configuration["SecurityKey"]));
                var expires = DateTime.Now.AddDays(30);//
                var token = new JwtSecurityToken(
                            issuer: _configuration["issuer"],
                            audience: _configuration["audience"],
                            claims: claims,
                            notBefore: DateTime.Now,
                            expires: expires,
                            signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256));

                //生成Token
                string jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
                result.code = 200;
                result.data = new TokenObj() { token = jwtToken, expires = expires.ToFileTimeUtc() };
                result.message = "授权成功!";
                return result;
            }
            catch (Exception ex)
            {
                result.message = ex.Message;
                result.code = 400;
                // logger.Error("获取访问令牌时发生错误!", ex);
                return result;
            }
        }

下面添加Swagger UI并验证JWT认证。

3、添加Swashbuckle

Get started with Swashbuckle and ASP.NET Core

按照上面链接添加Swagger UI

  • 在Swagger中添加JWT认证功能

在startup.cs文件中的ConfigureServices方法中的services.AddSwaggerGen配置末尾添加以下代码

                c.AddSecurityDefinition("Bearer", 
                    new ApiKeyScheme {
                        In = "header",
                        Description = "请输入OAuth接口返回的Token,前置Bearer。示例:Bearer {Roken}",
                        Name = "Authorization",
                        Type = "apiKey"
                    });
                c.AddSecurityRequirement(
                    new Dictionary<string, IEnumerable<string>>
                    {
                        { "Bearer",
                          Enumerable.Empty<string>()
                        },
                    });

4、调试

在项目内置的ValuesController中给Get方法添加[Authorize]标签,如下图所示:

调试项目,进入Swagger UI页面,url为http://localhost:<port>/swagger进行调试。

直接请求GET  /api/Values

点击Try it out,再点Execute可见Server response的code是401,未授权: (Unauthorized)

我们尝试OAuth接口获取Token,user password随便输入,可以看到返回的数据有一个token。我们将它复制备用。

点击页面上端的Authorize按钮,按如下图格式输入我们刚刚复制的token,前面带有Bearer,与复制的token间隔一个空格。

再点击Authorize按钮,关闭对话框,然后再去尝试GET  /api/Values接口吧!

返回结果正确,DONE!!!!

生成的token超长,尚未知道如何刷新token。