基于Python flask-sqlalchemy的SQLServer数据库管理平台

适应场景:

主要用于帮助DBA自动化很多日常工作,包括:

  • 数据库状态监控
  • 性能问题诊断
  • 日志分析
  • 自动巡检
  • 问题告警

系统截图:

main.py

from flask import Blueprint, render_template, request, flash, redirect, url_for
from flask_login import login_required
from app.models.datasource import DataSource
from app import db

bp = Blueprint('main', __name__)

@bp.route('/')
@login_required
def index():
    datasources = DataSource.query.all()
    return render_template('index.html', datasources=datasources)

@bp.route('/datasource', methods=['GET', 'POST'])
@login_required
def datasource_list():
    datasources = DataSource.query.all()
    return render_template('datasource/list.html', datasources=datasources)

@bp.route('/datasource/add', methods=['GET', 'POST'])
@login_required
def datasource_add():
    if request.method == 'POST':
        try:
            datasource = DataSource(
                name=request.form['name'],
                host=request.form['host'],
                port=int(request.form['port']),
                database=request.form['database'],
                username=request.form['username'],
                password=request.form['password']
            )
            db.session.add(datasource)
            db.session.commit()
            flash('数据源添加成功', 'success')
            return redirect(url_for('main.datasource_list'))
        except Exception as e:
            flash(f'添加失败: {str(e)}', 'danger')
    return render_template('datasource/form.html')

@bp.route('/datasource/edit/<int:id>', methods=['GET', 'POST'])
@login_required
def datasource_edit(id):
    datasource = DataSource.query.get_or_404(id)
    if request.method == 'POST':
        try:
            datasource.name = request.form['name']
            datasource.host = request.form['host']
            datasource.port = int(request.form['port'])
            datasource.database = request.form['database']
            datasource.username = request.form['username']
            if request.form['password']:  # 只在提供新密码时更新
                datasource.password = request.form['password']
            db.session.commit()
            flash('数据源更新成功', 'success')
            return redirect(url_for('main.datasource_list'))
        except Exception as e:
            flash(f'更新失败: {str(e)}', 'danger')
    return render_template('datasource/form.html', datasource=datasource)

@bp.route('/datasource/delete/<int:id>')
@login_required
def datasource_delete(id):
    datasource = DataSource.query.get_or_404(id)
    try:
        db.session.delete(datasource)
        db.session.commit()
        flash('数据源删除成功', 'success')
    except Exception as e:
        flash(f'删除失败: {str(e)}', 'danger')
    return redirect(url_for('main.datasource_list'))

@bp.route('/datasource/toggle/<int:id>')
@login_required
def datasource_toggle(id):
    datasource = DataSource.query.get_or_404(id)
    try:
        datasource.is_active = not datasource.is_active
        db.session.commit()
        flash('状态更新成功', 'success')
    except Exception as e:
        flash(f'更新失败: {str(e)}', 'danger')
    return redirect(url_for('main.datasource_list')) 

monitor.py

from flask import Blueprint, render_template, jsonify
from flask_login import login_required
from app.models.datasource import DataSource
from app.services.monitor_service import MonitorService

bp = Blueprint('monitor', __name__, url_prefix='/monitor')

@bp.route('/status/<int:id>')
@login_required
def status(id):
    datasource = DataSource.query.get_or_404(id)
    status = MonitorService.get_database_status(id)
    return render_template('monitor/status.html', datasource=datasource, status=status)

@bp.route('/api/status/<int:id>')
@login_required
def api_status(id):
    status = MonitorService.get_database_status(id)
    return jsonify(status) 

monitor_service.py

# import pyodbc  # 暂时注释掉
from app.models.datasource import DataSource
import datetime

class MonitorService:
    @staticmethod
    def get_database_status(datasource_id):
        datasource = DataSource.query.get(datasource_id)
        if not datasource:
            return None
            
        # 模拟获取更丰富的数据库状态信息
        return {
            'basic_info': {
                'database_id': 1,
                'name': datasource.database,
                'state': 'ONLINE',
                'recovery_model': 'FULL',
                'compatibility_level': '150',
                'collation': 'Chinese_PRC_CI_AS',
                'created_time': '2023-01-01 08:00:00',
                'last_backup_time': '2024-03-10 03:00:00'
            },
            'size_info': {
                'data_size': '1024 MB',
                'log_size': '256 MB',
                'total_size': '1280 MB',
                'data_space_used': 75.5,  # 百分比
                'log_space_used': 45.2,   # 百分比
                'unallocated_space': '512 MB'
            },
            'performance': {
                'cpu_usage': 35.5,        # 百分比
                'memory_usage': 4096,      # MB
                'buffer_cache_hit': 98.5,  # 百分比
                'page_life_expectancy': 1200,  # 秒
                'batch_requests': 450,     # 每秒
                'user_connections': 85,
                'active_transactions': 12,
                'blocked_processes': 0,
                'deadlocks': 0,
                'lock_waits': 2
            },
            'io_stats': {
                'reads_per_sec': 250,
                'writes_per_sec': 120,
                'io_pending': 0,
                'io_stall_ms': 150,
                'read_latency_ms': 3,
                'write_latency_ms': 5
            },
            'availability': {
                'uptime': '15 days 6 hours',
                'last_restart': '2024-02-25 00:00:00',
                'failovers_last_24h': 0,
                'mirror_status': 'Not Configured'
            },
            'alerts': [
                {
                    'type': 'warning',
                    'message': '数据文件空间使用率超过75%',
                    'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                }
            ]
        }

    @staticmethod
    def get_database_status_real(datasource_id):
        datasource = DataSource.query.get(datasource_id)
        if not datasource:
            return None
            
        conn_str = (
            f"DRIVER={{ODBC Driver 17 for SQL Server}};"
            f"SERVER={datasource.host},{datasource.port};"
            f"DATABASE={datasource.database};"
            f"UID={datasource.username};"
            f"PWD={datasource.password}"
        )
        
        try:
            conn = pyodbc.connect(conn_str)
            cursor = conn.cursor()
            
            # 获取数据库状态
            cursor.execute("""
                SELECT 
                    database_id,
                    name,
                    state_desc,
                    recovery_model_desc,
                    total_size = str(size*8/1024)+' MB'
                FROM sys.databases
                WHERE name = ?
            """, datasource.database)
            
            status = cursor.fetchone()
            
            # 获取性能指标
            cursor.execute("""
                SELECT TOP 1
                    cpu_time,
                    total_worker_time,
                    total_physical_reads,
                    total_logical_writes,
                    total_logical_reads
                FROM sys.dm_exec_query_stats
                ORDER BY total_worker_time DESC
            """)
            
            performance = cursor.fetchone()
            
            return {
                'status': {
                    'database_id': status[0],
                    'name': status[1],
                    'state': status[2],
                    'recovery_model': status[3],
                    'size': status[4]
                },
                'performance': {
                    'cpu_time': performance[0],
                    'worker_time': performance[1],
                    'physical_reads': performance[2],
                    'logical_writes': performance[3],
                    'logical_reads': performance[4]
                }
            }
            
        except Exception as e:
            return {'error': str(e)}
        finally:
            if 'conn' in locals():
                conn.close() 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/968344.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TensorRT 8.6.1教程1-TensorRT简介

区分计算节点和数据节点 视频 TensorRT 教程 | 基于 8.6.1 版本 | 第一部分_哔哩哔哩_bilibili cookbook

MySQL创建存储过程和存储函数

【图书推荐】《MySQL 9从入门到性能优化&#xff08;视频教学版&#xff09;》-CSDN博客 《MySQL 9从入门到性能优化&#xff08;视频教学版&#xff09;&#xff08;数据库技术丛书&#xff09;》(王英英)【摘要 书评 试读】- 京东图书 (jd.com) MySQL9数据库技术_夏天又到了…

【项目总结】易到家家政服务平台 —— 派单调度(7)

派单调度需求分析 在抢单业务中&#xff0c;用户下单成功由服务人员或机构进行抢单&#xff0c;抢单成功服务人员上门服务&#xff0c;除了抢单业务系统还设计了派单业务&#xff0c;由系统根据用户订单的特点自动派给合适的服务人员。 流程如下&#xff1a; 首先获取待分配…

visual studio 在kylin v10上跨平台编译时c++标准库提示缺少无法打开的问题解决

情况1&#xff1a;提示无法打开 源文件 "string"之类导致无法编译 情况2:能编译&#xff0c;但无法打开这些库文件或标准库使用提示下划红色问题 解决方案&#xff1a; 一、通过工具->选项->跨平台里&#xff0c;在“远程标头IntelliSense管理器”更新下载一下…

SpringCould+vue3项目的后台用户管理的CURD【Taurus教育平台】

文章目录 一.SpringCouldvue3项目的后台用户管理的CURD【Taurus教育平台】 1.1 背景 二.用户列表&#xff08;分页查询&#xff09; 2.1 前端Vue3 &#xff08;Vue3-Element-Admin&#xff09;2.2 后端SpringCould 处理 三. 用户信息删除 3.1 前端Vue3 &#xff08;Vue3-Eleme…

Eclipse 插件开发相关概念

整理了Eclipse插件开发的概念&#xff0c;用于熟悉入门 SWT&#xff08;Standard Widget Toolkit&#xff09;标准图形工具箱 Java开发的GUI程序技术&#xff0c;由Eclipse开发&#xff0c;相比AWT、Swing更美观&#xff1b;对于目标平台上已经有的控件&#xff0c;SWT会直接使…

算法之 数论

文章目录 质数判断质数3115.质数的最大距离 质数筛选204.计数质数2761.和等于目标值的质数对 2521.数组乘积中的不同质因数数目 质数 质数的定义&#xff1a;除了本身和1&#xff0c;不能被其他小于它的数整除&#xff0c;最小的质数是 2 求解质数的几种方法 法1&#xff0c;根…

AndroidStudio查看Sqlite和SharedPreference

1.查看Sqlite 使用App Inspection&#xff0c;这是个好东西 打开方式&#xff1a;View → Tool Windows → App Inspection 界面如图&#xff1a; App inspection不但可以看Sqlite还可以抓包network和background task连抓包工具都省了。 非常好使 2.查看sharedPreference 使…

谈一谈数据库中的死锁问题

文章目录 死锁是什么&#xff1f;死锁的四个必要条件避免死锁的策略 本篇文章是基于《MySQL45讲》来写的个人理解与感悟。 死锁是什么&#xff1f; 死锁是指两个或两个以上的进程在执行过程中&#xff0c;由于竞争资源或者由于彼此通信而造成的一种阻塞的现象。若无外力作用&a…

网络工程师 (31)VLAN

前言 VLAN&#xff08;Virtual Local Area Network&#xff09;即虚拟局域网&#xff0c;是一种将物理局域网划分成多个逻辑上独立的虚拟网络的技术。 一、定义与特点 定义&#xff1a;VLAN是对连接到的第二层交换机端口的网络用户的逻辑分段&#xff0c;不受网络用户的物理位置…

从深入理解 netty——》AI

想了很久&#xff0c;准备写一个系列从深入理解 netty——》AI。 先说下为啥要从netty开始&#xff0c;看看netty的重要性 rocketmq异步消息组件nacos微服务注册中心spring cloud gateway网关redission分布式缓存es全文检索sentinel流量控制&#xff0c;服务保护seata分布式…

从 0 开始本地部署 DeepSeek:详细步骤 + 避坑指南 + 构建可视化(安装在D盘)

个人主页&#xff1a;chian-ocean 前言&#xff1a; 随着人工智能技术的迅速发展&#xff0c;大语言模型在各个行业中得到了广泛应用。DeepSeek 作为一个新兴的 AI 公司&#xff0c;凭借其高效的 AI 模型和开源的优势&#xff0c;吸引了越来越多的开发者和企业关注。为了更好地…

在anaconda环境中构建flask项目的exe文件

一、创建并激活虚拟环境 conda create -n flask_env python3.9 # python版本根据项目需求安装 conda activate flask_env # 激活环境二、安装必要依赖 推荐使用conda&#xff0c;pip没尝试过&#xff0c;但是deepseek给出了命令 conda install flask …

腾讯云服务器中Ubuntu18.04搭建python3.7.0与TensorFlow1.15.0与R-4.0.3环境

所有踩过的坑&#xff0c;都化成了这条平坦的路 云服务器配置 基础配置选择竞价实例&#xff08;便宜/需求小&#xff09; 选择地区&#xff08;距离自己近的就行&#xff09; 实例配置选择异构计算&#xff08;能力较强&#xff0c;性价比高&#xff09;根据GPU显存需求选择…

金融风控项目-1

文章目录 一. 案例背景介绍二. 代码实现1. 加载数据2. 数据处理3. 查询 三. 业务解读 一. 案例背景介绍 通过对业务数据分析了解信贷业务状况 数据集说明 从开源数据改造而来&#xff0c;基本反映真实业务数据销售&#xff0c;客服可以忽略账单周期&#xff0c;放款日期账单金…

JAVA安全—Shiro反序列化DNS利用链CC利用链AES动态调试

前言 讲了FastJson反序列化的原理和利用链&#xff0c;今天讲一下Shiro的反序列化利用&#xff0c;这个也是目前比较热门的。 原生态反序列化 我们先来复习一下原生态的反序列化&#xff0c;之前也是讲过的&#xff0c;打开我们写过的serialization_demo。代码也很简单&…

基于Spring Boot的医院挂号就诊系统【免费送】

基于Spring Boot的医院挂号就诊系统 效果如下&#xff1a; 系统登陆页面 系统主页面 挂号页面 客服页面 挂号管理页面 公告信息管理页面 审核页面 在线咨询管理页面 研究背景 随着医疗技术的不断发展和人们健康意识的提高&#xff0c;医院作为提供医疗服务的核心机构&#x…

玩转适配器模式

文章目录 解决方案现实的举例适用场景实现方式适配器模式优缺点优点:缺点:适配器模式可比上一篇的工厂模式好理解多了,工厂模式要具有抽象的思维。这个适配器模式,正如字面意思,就是要去适配某一件物品。 假如你正在开发一款股票市场监测程序, 它会从不同来源下载 XML 格…

栈的简单介绍

一.栈 栈是一种先进后出的结构&#xff1a;&#xff08;先出来的是45&#xff0c;要出12就必须先把前面的数据全部出完。&#xff09; 2.实例化一个栈对象&#xff1a; 3.入栈&#xff1a; 4.出栈&#xff1a;&#xff08;当走完pop就直接弹出45了。&#xff09; 5.出栈的…

【Java】-【面试】-【Java进阶】

一、分布式 1、分布式锁 2、分布式ID 3、分布式事务