在matlab中采用封装类的形式将数据存入数据库

前言说明

  1. 本文采用的odbc方式进行
  2. 本文采用matlab类的形式,也可以自行用面向过程的思想,编写函数。封装为类,仅仅为了方便调用。

Sqlserver数据库表设计

在这里插入图片描述

封装类 DBHelperForMatlab类

在matlab中新建DBHelperForMatlab类,这里仅写了插入数据函数。

  • 所有需要插入数据库时候,统一调用该代码。在数据库账户变更后,只需要改变本类,不需要改变其他代码。当然,单独写个函数文件,也是可行的。
  • 与matlab自带的insert.m函数相比,封装后,会有返回值,提示保存是否成功等。由于insert.m函数本身并没有返回值,这是当调通insert函数后,默认cherub数据成功。
  • 直接调用该类的方法,用户不用每次都要写关闭数据库连接事件。
  • 不足matlab 类效率低,一致被人诟病;尤其在循环调用时,这个可以亲自测试

具体代码如下:

classdef DBHelperForMatlab
    % DBHelperForMatlab  用matlab通过odbc方式建立的数据库操作帮助类
    % 参考 odbc方式数据库操作 https://blog.csdn.net/cxrsdn/article/details/82632863
    % 参考 Matlab面向对象编程实例 https://blog.csdn.net/miscclp/article/details/26090137
    % 参考 matlab规范 https://blog.csdn.net/qq_15971883/article/details/82884353
    % 参考odbc的详细配置方式 https://www.bbsmax.com/A/MAzAvjreJ9/
   properties   (GetAccess ='private',SetAccess ='private') %设置私有变量,不能被该类外访问
      datasource= 'CustomTest';  %前面设置的数据源名称(实际上应该是封装了访问数据所在电脑的ip地址以及数据库名称),告诉matlab要访问操作的数据库位于哪台计算机(ip地址)中的那个数据库;  
      userName='s22222a'; %数据库用户账户
      password ='13344444446'; %登录密码     
    end
    
    methods (Static)   
        % DBHelperForMatlab 显式定义构造函数
        function obj=DBHelperForMatlab()         
        end
        %  InsertDB 将数据插入到数据库表中
        %tableName 数据库表名
        %colnames 数据库列名(字段)
        %data   与数据库列名相对应的数据,注意数据格式要和数据库中的字段类型类似;数值类型,字符类型
        % 返回值 -1:数据库连接失败,没有打开数据库。 1:数据插入成功
         function exeState = InsertDB(tableName,colnames,data)
            obj=DBHelperForMatlab();             
             %CanOPen  判断是否成功打开数据库链接,成功返回1,失败返回0          
            connection=database( obj.datasource,obj.userName,obj.password);
            openState=isopen(connection);
            if openState==0
                exeState=-1; %-1表示没有打开数据库。
            else 
                % https://ww2.mathworks.cn/help/database/ug/database.odbc.connection.execute.html
                insert(connection,tableName,colnames,data);  
                commit(connection);   % 将更新保存到数据库中 
                exeState=1;  % 1 成功将数据插入到数据库。
            end
             close(connection);
         end
    end
end

调用 DBHelperForMatlab类,插入数据库

function  result=testFun()
% testFun 测试封装的插入数据库函数 
arr={'id','StuName','ClassId','age'};  %表中的字段,前2个字段是字符型,后2个字段是数值型 
da={'f999','sd', 124,394};   %2个字段是字符型,后2个字段是数值型 ;如果字段类型都是数值,也可以用矩阵等形式做参数,如 da=[12 3 4]
 result = DBHelperForMatlab.InsertDB( '[CustomTest].[dbo].TStudent', arr,da) %如果有多行数据需要插入,可以循环调用。
 end 

matlab中的databasetool中的insert.m函数的部分注释

function insert( connect,tableName,fieldNames,data )
%INSERT Export MATLAB data into database table.
%   INSERT(CONNECT,TABLENAME,FIELDNAMES,DATA).
%   CONNECT is an object of type database.ODBCConnection, FIELDNAMES
%   is a cell array of database column names, TABLENAME is the
%   database table and DATA is a cell array, numeric matrix,
%   structure, dataset, or table.
%
%   If DATA is a structure, dataset, or table, it needs to be formatted in
%   a certain way. Each field in the structure or each variable in the
%   dataset or table must be a cell array or double vector of size m*1
%   where m is the number of rows to be inserted.
%
%   Example:
%
%   The following INSERT command inserts the contents of
%   the cell array in to the database table yearlySales
%   for the columns defined in the cell array colNames.
%
%   insert(conn,'yearlySales', colNames, monthlyTotals);
%
%   where, the cell array colNames contains the value:
%   colNames = {'salesTotal'};
%
%   'monthlyTotals' is a cell array containing the data to be
%   inserted into the database table 'yearlySales'
%
%   See also connection/datainsert, connection/fastinsert

%   Copyright 1984-2016 The MathWorks, Inc.
%   山南编辑,补充部分中文翻译。201982018:12:53

% Check for valid connection
if(~isopen(connect))
  % shannan汉化 error(message('database:database:invalidConnection'));
    error(message('连接数据库失败!'));  
end

%Input validation
p = inputParser;

p.addRequired('tableName', @database.internal.utilities.DatabaseUtils.tablenameCheck);
p.addRequired('fieldNames', @database.internal.utilities.DatabaseUtils.fieldnamesCheck);
p.addRequired('data', @database.internal.utilities.DatabaseUtils.insertDataCheck);

%Catch Input Validation errors
p.parse(tableName,fieldNames,data);

tablename = char(p.Results.tableName);
fieldNames = cellstr(p.Results.fieldNames);
data = p.Results.data;

%Get size of data
switch class(data)
    
    case {'int8','uint8','int16','uint16','uint32','int32','int64','uint64','single'}
        data = double(data);
        numberOfCols = size(data,2);
        if numberOfCols ~= length(fieldNames)
            error(message('database:insert:numerofColumnsMismatch'))
        end
        
    case {'cell','double'}
        numberOfCols = size(data,2);
        if numberOfCols ~= length(fieldNames)
            error(message('database:insert:numerofColumnsMismatch'))
        end
        
    case 'struct'
        sflds = fieldnames(data);
        if length(sflds) ~= length(fieldNames)
            error(message('database:insert:numerofColumnsMismatch'))
        end
        
        fchk = setxor(sflds,fieldNames);
        if ~isempty(fchk)
          error(message('database:insert:fieldMismatch','Structure fields'))
        end

        % order of columnnames and struct variable names should match
        for i=1:length(fieldNames)

          if strcmpi(sflds{i}, fieldNames{i}) == 0
            error(message('database:insert:fieldMismatch','Structure fields'))
          end

        end
    
        numberOfCols = length(sflds);
        
        data = database.internal.utilities.DatabaseUtils.validateStruct(data);
        
    case 'dataset'
        dSummary = summary(data);
        sflds = {dSummary.Variables.Name};
        fchk = setxor(sflds,fieldNames);
        if ~isempty(fchk)
            error(message('database:insert:fieldMismatch','Dataset variables'))
        end
        
        % order of columnnames and struct variable names should match
        for i=1:length(fieldNames)
          if strcmpi(sflds{i}, fieldNames{i}) == 0
            error(message('database:insert:fieldMismatch','Dataset variables'))
          end
        end
        
        numberOfCols = length(sflds);
        
        
        %convert dataset to struct before pushing to the C API
        data = dataset2struct(data, 'AsScalar', true);
        
        data = database.internal.utilities.DatabaseUtils.validateStruct(data);
        
    case 'table'
        sflds = data.Properties.VariableNames;
        
        if length(sflds) ~= length(fieldNames)
            error(message('database:insert:numerofColumnsMismatch'))
        end
        
        fchk = setxor(sflds,fieldNames);
        if ~isempty(fchk)
          error(message('database:insert:fieldMismatch','Table variables'))
        end

        % order of columnnames and struct variable names should match
        for i=1:length(fieldNames)

          if strcmpi(sflds{i}, fieldNames{i}) == 0
            error(message('database:insert:fieldMismatch','Table variables'))
          end

        end
        
        numberOfCols = length(sflds);
        
        %convert table to struct before pushing to the C API
        data = table2struct(data, 'ToScalar',true);
        
        data = database.internal.utilities.DatabaseUtils.validateStruct(data);
        
    otherwise
        error(message('database:insert:inputDataError'))
        
end

% Create INSERT query to be prepared.
fieldNamesString = '';
parameterString = '';

% Create the field name string for the INSERT statement .. this defines the
% fields in the database table that will be receive data.
% Also build variable ?'s string for later set* commands
% 根据用户传入的表名、列字段 拼接成 标准SQL语句 insert [TStudent](id,StuName,ClassId,age) values (?,?,?,?)
% 注意该标准SQL语句并没有赋值,而是用?代替

for i=1:numberOfCols
    if ( i == numberOfCols)
        fieldNamesString = [ fieldNamesString fieldNames{i}];  %#ok
        parameterString = [parameterString '?)'];                          %#ok
    else
        fieldNamesString = [ fieldNamesString fieldNames{i} ',' ]; %#ok
        parameterString = [parameterString '?,'];                              %#ok
    end
end

try
    
    %Get Database Product name
    dbProdName = connect.DatabaseProductName;
    
    validDB = 0;
    if strcmpi(dbProdName, 'Oracle') || strcmpi(dbProdName, 'PostgreSQL') || strcmpi(dbProdName, 'Microsoft SQL Server')
        validDB = 1;
    end

    if validDB
      
        transactionStmt = connect.Handle.createStatement;
        % Save the current setting and turn off auto-commit
        oldState = connect.AutoCommit;
        connect.AutoCommit = 'off';
    end
    
    %Using the faster ODBC API method for MySQL 
    if(strcmpi(dbProdName, 'MySQL') || strcmpi(dbProdName, 'Access'))
      
        %Create SELECT string
        selectString = ['select ' fieldNamesString ' from ' tablename ' where 1=2'];
        
        %Create new statement for INSERT
        insertStmt = connect.Handle.createStatement;
        insertStmt.insertData(dbProdName, selectString, data);
        
        %close both statements
        insertStmt.closeStatement;
        
    else
        
        % Create the SQL statement 
        parameterizedInsertString = [ 'INSERT INTO '  tablename ' (' fieldNamesString ') ' 'VALUES ( ' parameterString ];   
        %Need to run exec query to get column attributes
        curs = exec(connect,['select ' fieldNamesString ' from ' tablename ' where 1=2']);        
        if ~isempty(curs.Message)
            error(message('database:insert:insertError', curs.Message))
        end
        
        curs = fetch(curs, 1);
        
        if ~isempty(curs.Message)
            error(message('database:insert:insertError', curs.Message))
        end
        
        %Create new statement for INSERT
        insertStmt = connect.Handle.createStatement;
     % 完整的数据库赋值语句是下面这句。 data是数据库表各字段所对应的具体值
        insertStmt.insertData(curs.Statement,parameterizedInsertString, data);        
        %close both statements
        insertStmt.closeStatement;
        close(curs);  
    end        
    
    % close transaction stmt
    if validDB 
      if strcmpi(oldState, 'on')
        % Commit changes 
        transactionStmt.executeQuery('COMMIT');
      end
      
      % Close the transaction statement
      transactionStmt.closeStatement;
      % Reset auto-commit to original value
      connect.AutoCommit = oldState;
    end
    

    
catch e
    %close statements and then throw error
    
    if(exist('curs', 'var'))
        close(curs);
    end
    
    if(exist('insertStmt', 'var'))
        insertStmt.closeStatement;
    end
    
    if validDB 
        if strcmpi(oldState, 'on')
          % Rollback changes in case of failures
          transactionStmt.executeQuery('ROLLBACK');
        end
        % Close the transaction statement
        transactionStmt.closeStatement;
        % Reset auto-commit to original value
        connect.AutoCommit = oldState;
    end
  
    % Reset auto-commit to original value
    throw(e);
end

end


原创Matlab通过ODBC的方式调用数据库-CreateSchema.m 以下内容为Matlab中文论坛会员,Godman原创。 如果需要转载,请联系Godman会员: 如有疑问可以邮件联系 tntuyh@163.com Godman 2009.3.30 晚 Good Luck! —————————————————————————————————————————— Matlab数据库编程指南-Godman Matlab数据库链接有三种方法,本文只讲述其中以ODBC的方式进行链接。 本文件包含四部分,其中第三部分为我自己写的一些数据库函数操作的函数,第四部分为网上的一些资料。 第一部分:读取数据其相关信息查看 1.        配置数据源 “控制面板”----“管理工具”——“数据源(ODBC)”——“添加”——“创建数据源名称和选择数据库文件”(具体操作见GIF图片操作)。 2.        建立链接对象——database 调用格式: conna=database; 如conna=database;其中SampleDB为上文中创建的数据源名称,当默认情况下,数据库文件的username和password为空。 3.        建立并打开游标——exec 调用格式: curs=exec; 如curs=exec 其中conna为上文中链接对象,select * from database表示从表database中选择所有的数据. 4.        把数据库中的数据读取到Matlab中——fetch 调用格式: curs=fetch; Data=curs.Data;%把读取到的数据用变量Data保存. 如curs=fetch; 把所有的数据一次全部读取到Matlab中,RowLimit为每次读取的数据参数的行数,默认为全部读取,但是全部读取会很费时间(和计算机性能很大关系)。 上述四点是matlab数据库文件中读取数据matlab中的基本步骤。 5.        数据返回类型 从数据库中读取数据matlab有三种数据类型(默认为元胞类型cellarray),分别为元胞类型(cellarray),数字型(numeric),结构型(structure)。可以在链接数据库之前通过setdbprefs函数来进行设置。如果数据库文件中全部是数值型数据时最好采用numeric型的数据,这样可以使得读取速度大幅提高,特别是在大型数据读取时非常明显。我曾经从数据库中读取过100万个数据,用cellarray时用了16s,但是用numeric时却只用了8s,速度提高很大啊,对电脑配置不好的来说,很有帮助的。(还有我的电脑很烂,1.3GHz,384M内存,可能让大家见笑了…….) 调用格式: setdbprefs 6.        养成良好习惯,随手关闭链接对象和游标——close 当不再使用数据库的链接对象时要及时关闭,这样才能及时的释放出内存,而且每次链接后所需要的内存量是非常大的,要是不及时关闭的话对后续计算的影响将非常非常的大。 调用格式: close close 7.        查看数据相关信息 Rows-查看数据行数 调用格式:numrows=rows Cols——查看数据列数 调用格式:numcols=cols Attr——查看数据属性 调用格式:attribute=attr
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值