MySQL 存儲過程 自定義函數 原

一. 定義

        存儲過程 Procedure 是一組爲了完成特定功能的 SQL 語句集合,經編譯後存儲在數據庫中,用戶通過指定存儲過程的名稱並給出參數來執行。存儲過程中可以包含邏輯控制語句和數據操縱語句,它可以接受參數、輸出參數、返回單個或多個結果集以及返回值。

        以上是官方的定義。簡單來說,如果把sql當成是代碼,其實存儲過程就相當於函數。把一組具備特定功能的sql語句封裝成起來而已。所以他的本質是爲了更好的執行對數據庫的操作。那麼好在哪裏呢?

二. 存儲過程的優勢

        1. 性能。存儲過程在創建時就已經在數據庫服務器中編譯好並存儲起來,調用時只需提供過程名和參數,就可以直接使用。而sql語句,沒執行一句就要編譯一次,這在sql語句發送並不頻繁的情況下還好,但是如果短時間大量發送sql語句的情況下,不僅會降低網絡性能也會增加數據庫負擔。

        2. 可完成更復雜的數據庫控制。由於存儲過程中可以包含邏輯控制語句和數據操縱語句,類似遍歷、if這種邏輯可以直接卸載過程中。

        3.我在程序中寫了一段代碼,發送一千條sql插入語句到本地數據庫,大概花了6672ms,而在存儲過程中只花了4689ms。以下分別是代碼和存儲過程sql:

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public static final String INSERT_SQL="insert into user (id, name, age) values(?,?,?)";

    public void insert(){
        long begin = System.currentTimeMillis();
        for (int i = 600000; i < 601000; i++) {
            jdbcTemplate.update(INSERT_SQL,i,"林"+i,10+Math.random()*10);
        }
        long end = System.currentTimeMillis();
        System.out.println(end-begin);
    }
CREATE PROCEDURE test_insert2 () 

BEGIN
DECLARE i INT DEFAULT 601000;
WHILE i<602000
DO
insert into `user` (id,NAME,age) values (i,CONCAT('林',i),18); 
SET i=i+1;
END WHILE;
COMMIT;
END;

CALL test_insert2()

三. 存儲過程基本語法和變量講解

        1. delimiter //     該語句指定MySQL把“//”當作分隔符。也就是說,如果你在MySQL client中輸入這句,則“;”符號不再被當作結束符。

        2. create procedure getAllUser()    表示創建存儲過程,其名爲getAllUser()。

        3. call getAllUser ;       調用存儲過程getAllUser。

        4. drop procedure getAllUser;   刪除存儲過程。

        5. begin...end  之間編寫過程體,即寫sql語句和邏輯代碼。

        6. 存儲過程根據需要可能會有輸入、輸出、輸入輸出參數,如果有多個參數用","分割開。MySQL存儲過程的參數用在存儲過程的定義,共有三種參數類型,IN,OUT,INOUT:

  • IN參數的值必須在調用存儲過程時指定,在存儲過程中修改該參數的值不能被返回,爲默認值
  • OUT:該值可在存儲過程內部被改變,並可返回
  • INOUT:調用時指定,並且可被改變和返回

四. 分別在MySQL client中和Navicat中創建存儲過程

  • 在client創建一個查詢所有user表記錄的過程。

        

        最後輸入 還原分隔符爲 “;”

        調用過程

        刪除過程

  • 在Navicat中創建一個插入user表數據的存儲過程 ,並且傳遞兩個參數

        

        右鍵新建函數,選擇過程

        

        

        在這裏寫邏輯語句吧,完整如下:

BEGIN

DECLARE i INT DEFAULT initValue;
WHILE i<=endValue
DO
insert into `user` (id,NAME,age) values (i,CONCAT('林',i),18); 
SET i=i+1;
END WHILE;
COMMIT;

END

        這裏的意思是 把第一個參數賦給變量i,當i小於第二個參數值時,一直進行while循環,每次循環i+1。

  Navicat裏面點擊sql預覽可以看到完整的代碼:

 按下ctrl+s保存:

然後運行,輸入兩個參數,逗號隔開:

就可以插入數據了。

五. 在java程序中調用存儲過程

    @Autowired
    private DataSource dataSource;
    public List<User> getUser() {
        List<User> users = new ArrayList<User>(10000);
        User user = new User();
        try {
            CallableStatement callableStatement = dataSource.getConnection().prepareCall("{call getUser}");
            ResultSet rs = null; //執行查詢操作,並獲取結果集
            rs = callableStatement.executeQuery();
            while (rs.next()){
                user.setName(rs.getString("name"));
                user.setAge(rs.getInt("age"));
                user.setId(rs.getInt("id"));
                users.add(user);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return users;
    }

調用一個getUser()的存儲過程,並將結果封裝成實體。主要是 CallableStatement callableStatement = dataSource.getConnection().prepareCall("{call getUser}");這句代碼。這裏我認爲應該有更成熟的調用方式纔對,但是我也懶得找資料了。反正原理都一樣。

六. 自定義函數

mysql的自定義函數其實就是我們自己去定義類似sum(...)、max(...)這種函數,很簡單,創建起來跟存儲過程差不多,就不多做講解了。

create function sum1(x int,y int) returns int(20)

begin 

        //編寫函數體

return xxx ;

end ; 

使用  select sum1(215,555)

刪除  drop sum1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章