赞
踩
golang办公工作流workflow利用js-ojus/flow做测试——系列二
golang办公流程引擎初体验js-ojus/flow——系列三
golang办公流程引擎初体验js-ojus/flow——系列四
流程大致是这样的:
1.管理员定义好流程类型doctype,这个下面再分流程类型workflow1,workflow2,workflow下再具体分为节点node1,node2,
再定义通用的状态state,通用的动作action,以及根据workflow1下的节点来定义流程走向transition,
再定义contex里的用户-组-角色-权限
2.对于一个要走流程的文件document_001数据表的某个文件,先建立一个document,再给它定义多个事件event,根据workflow1下的节点多少来定义,节点数-1个事件,也就是transition的个数。这个事件就是定义将document_001里的某个文件从状态1 state1改为state2的动作action。
3.开始走流程了,用事件event来修改document_001数据表里某个文件的状态,这个状态从state1变为state2,符合node1里的state1到node2里的state2,也符合transition里的state1——action1——state2
- package controllers
-
- import (
- "database/sql"
- "github.com/astaxie/beego"
- // "strings"
- // "testing"
- "fmt"
- _ "github.com/go-sql-driver/mysql"
- "github.com/js-ojus/flow"
- // "github.com/3xxx/meritms/models"
- // _ "github.com/mattn/go-sqlite3"
- // "github.com/astaxie/beego/httplib"
- // "github.com/astaxie/beego/logs"
- "log"
- )
-
- type MainController struct {
- beego.Controller
- }
-
- func (c *MainController) Get() {
- c.Data["Website"] = "beego.me"
- c.Data["Email"] = "astaxie@gmail.com"
- c.TplName = "index.tpl"
- }
-
- // var db *sql.DB
-
- // func init() {
- // driver, connStr := "mysql", "root:root@/flow"
- // tdb := fatal1(sql.Open(driver, connStr)).(*sql.DB)
- // // flow.RegisterDB(tdb)
-
- // if tdb == nil {
- // log.Fatal("given database handle is `nil`")
- // }
- // db = tdb
- // }
-
- // @Title show wf list
- // @Description show workflow page
- // @Success 200 {object} models.GetProductsPage
- // @Failure 400 Invalid page supplied
- // @Failure 404 articls not found
- // @router /workflow [get]
- //页面
- func (c *MainController) WorkFlow() {
- c.TplName = "merit/workflow.tpl"
- }
-
- // @Title get wf list
- // @Description get workflowlist by page
- // @Success 200 {object} models.GetProductsPage
- // @Failure 400 Invalid page supplied
- // @Failure 404 data not found
- // @router /flowtype [get]
- //管理员定义流程类型doctype、流程状态state、流程节点node、
- //流程动作action、流程流向transition、流程事件event
- func (c *MainController) FlowType() {
- // func init() {
- // orm.RegisterDriver("mysql", orm.DRMySQL)//注册驱动
- // orm.RegisterModel(new(Model))//注册 model
- // orm.RegisterDataBase("default", "mysql", "test:123456@/test?charset=utf8",30,30)//注册默认数据库
- //orm.RegisterDataBase("default", "mysql", "test:@/test?charset=utf8")//密码为空格式
- // }
-
- driver, connStr := "mysql", "travis@/flow?charset=utf8&parseTime=true"
- tdb := fatal1(sql.Open(driver, connStr)).(*sql.DB)
- if tdb == nil {
- log.Fatal("given database handle is `nil`")
- }
- db := tdb
- tx, _ := db.Begin()
- db.Close()
- //定义流程类型
- dtID1, err := flow.DocTypes.New(tx, "图纸设计流程")
- if err != nil {
- fmt.Println(err)
- }
- dtID2, err := flow.DocTypes.New(tx, "合同评审流程")
- if err != nil {
- fmt.Println(err)
- }
- beego.Info(dtID2)
- dtID3, err := flow.DocTypes.New(tx, "变更立项流程")
- if err != nil {
- fmt.Println(err)
- }
- beego.Info(dtID3)
- //定义流程状态
- dsID1, err := flow.DocStates.New(tx, "设计中...")
- if err != nil {
- fmt.Println(err)
- }
- dsID2, err := flow.DocStates.New(tx, "校核中...")
- if err != nil {
- fmt.Println(err)
- }
- dsID3, err := flow.DocStates.New(tx, "审查中...")
- if err != nil {
- fmt.Println(err)
- }
- flow.DocStates.New(tx, "批准中...")
- flow.DocStates.New(tx, "申报中...")
- flow.DocStates.New(tx, "评估中...")
- flow.DocStates.New(tx, "审批中...")
- //定义流程动作类型
- daID1, err := flow.DocActions.New(tx, "设计完成后提交", false) //改变状态设计中...为校核中...
- if err != nil {
- fmt.Println(err)
- }
- daID2, err := flow.DocActions.New(tx, "校核完成后提交", false)
- if err != nil {
- fmt.Println(err)
- }
- daID3, err := flow.DocActions.New(tx, "审查完成后提交", false)
- if err != nil {
- fmt.Println(err)
- }
- daID4, err := flow.DocActions.New(tx, "核定完成后提交", true)
- if err != nil {
- fmt.Println(err)
- }
- daID5, err := flow.DocActions.New(tx, "编制完成后提交", true)
- if err != nil {
- fmt.Println(err)
- }
- daID6, err := flow.DocActions.New(tx, "审批完成后提交", false)
- if err != nil {
- fmt.Println(err)
- }
- daID7, err := flow.DocActions.New(tx, "立项完成后提交", false)
- if err != nil {
- fmt.Println(err)
- }
-
- //添加流程规则1:oldstate1 action1 newstate2
- err = flow.DocTypes.AddTransition(tx, dtID1, dsID1, daID1, dsID2)
- if err != nil {
- beego.Error(err)
- }
- //添加流程规则2:oldstate2 action2 newstate3
- err = flow.DocTypes.AddTransition(tx, dtID1, dsID2, daID2, dsID3)
- if err != nil {
- beego.Error(err)
- }
-
- //定义流程类型doctype下的流程类型workflow
- workflowID1, err := flow.Workflows.New(tx, "图纸设计-三级校审流程", dtID1, dsID1) //初始状态是“设计中...”——校核——审查——完成
- if err != nil {
- fmt.Println(err)
- }
- beego.Info(workflowID1)
- workflowID2, err := flow.Workflows.New(tx, "图纸设计-二级校审流程", dtID1, dsID1) //初始状态是“设计中...”-“校核”——完成
- if err != nil {
- fmt.Println(err)
- }
- beego.Info(workflowID2)
- //定义合同评审下的流程类型:部门合同流程,总院合同流程
- //略
-
- //定义用户、组、角色、权限集合
- accessContextID1, err := flow.AccessContexts.New(tx, "Context")
- if err != nil {
- beego.Error(err)
- }
-
- //定义流程类型workflow下的具体每个节点node,用户对文件执行某个动作(event里的action)后,会沿着这些节点走
- // AddNode maps the given document state to the specified node. This
- // map is consulted by the workflow when performing a state transition
- // of the system.nodeID1
- _, err = flow.Workflows.AddNode(tx, dtID1, dsID1, accessContextID1, workflowID1, "图纸设计-三级校审流程-设计", flow.NodeTypeBegin)
- if err != nil {
- fmt.Println(err)
- }
- _, err = flow.Workflows.AddNode(tx, dtID1, dsID2, accessContextID1, workflowID1, "图纸设计-三级校审流程-校核", flow.NodeTypeLinear)
- if err != nil {
- fmt.Println(err)
- }
- _, err = flow.Workflows.AddNode(tx, dtID1, dsID3, accessContextID1, workflowID1, "图纸设计-三级校审流程-审查", flow.NodeTypeEnd)
- if err != nil {
- fmt.Println(err)
- }
- //定义用户-组-角色-权限关系
- res, err := tx.Exec(`INSERT INTO users_master(first_name, last_name, email, active)
- VALUES('秦', '晓川-1', 'email1@example.com', 1)`)
- if err != nil {
- log.Fatalf("%v\n", err)
- }
- uid, _ := res.LastInsertId()
- uID1 := flow.UserID(uid)
- _, err = flow.Groups.NewSingleton(tx, uID1)
-
- res, err = tx.Exec(`INSERT INTO users_master(first_name, last_name, email, active)
- VALUES('秦', '晓川-2', 'email2@example.com', 1)`)
- if err != nil {
- log.Fatalf("%v\n", err)
- }
- uid, _ = res.LastInsertId()
- uID2 := flow.UserID(uid)
- _, err = flow.Groups.NewSingleton(tx, uID2)
-
- res, err = tx.Exec(`INSERT INTO users_master(first_name, last_name, email, active)
- VALUES('秦', '晓川-3', 'email3@example.com', 1)`)
- if err != nil {
- log.Fatalf("%v\n", err)
- }
- uid, _ = res.LastInsertId()
- uID3 := flow.UserID(uid)
- _, err = flow.Groups.NewSingleton(tx, uID3)
-
- res, err = tx.Exec(`INSERT INTO users_master(first_name, last_name, email, active)
- VALUES('秦', '晓川-4', 'email4@example.com', 1)`)
- if err != nil {
- log.Fatalf("%v\n", err)
- }
- uid, _ = res.LastInsertId()
- uID4 := flow.UserID(uid)
- _, err = flow.Groups.NewSingleton(tx, uID4)
-
- gID1 := fatal1(flow.Groups.New(tx, "设计人员组", "G")).(flow.GroupID)
- gID2 := fatal1(flow.Groups.New(tx, "校核人员组", "G")).(flow.GroupID)
- fatal0(flow.Groups.AddUser(tx, gID1, uID1))
- fatal0(flow.Groups.AddUser(tx, gID1, uID2))
- fatal0(flow.Groups.AddUser(tx, gID1, uID3))
-
- fatal0(flow.Groups.AddUser(tx, gID2, uID2))
- fatal0(flow.Groups.AddUser(tx, gID2, uID3))
- fatal0(flow.Groups.AddUser(tx, gID2, uID4))
- roleID1 := fatal1(flow.Roles.New(tx, "设计人员角色")).(flow.RoleID)
- roleID2 := fatal1(flow.Roles.New(tx, "校核人员角色")).(flow.RoleID)
- //给角色role赋予action权限
- fatal0(flow.Roles.AddPermissions(tx, roleID1, dtID1, []flow.DocActionID{daID1, daID2, daID3, daID4}))
- fatal0(flow.Roles.AddPermissions(tx, roleID2, dtID1, []flow.DocActionID{daID1, daID2, daID3, daID4, daID5, daID6, daID7}))
- //给用户组group赋予角色role
- err = flow.AccessContexts.AddGroupRole(tx, accessContextID1, gID1, roleID1)
- if err != nil {
- beego.Error(err)
- }
- //将group和role加到accesscontext里——暂时不理解
- err = flow.AccessContexts.AddGroupRole(tx, accessContextID1, gID2, roleID2)
- if err != nil {
- beego.Error(err) //UNIQUE constraint failed: wf_ac_group_roles.ac_id已修补
- }
-
- tx.Commit() //这个必须要!!!!!!
-
- c.Data["json"] = "ok"
- c.ServeJSON()
- }
-
- // @Title post wf state
- // @Description post workflow state
- // @Success 200 {object} models.GetProductsPage
- // @Failure 400 Invalid page supplied
- // @Failure 404 data not found
- // @router /flowdocevent [get]
- //对具体文件进行流程初始化,对具体文件进行定义动作事件
- func (c *MainController) FlowDocEvent() {
- //连接数据库
- driver, connStr := "mysql", "travis@/flow?charset=utf8&parseTime=true"
- tdb := fatal1(sql.Open(driver, connStr)).(*sql.DB)
- if tdb == nil {
- log.Fatal("given database handle is `nil`")
- }
- db := tdb
- tx, err := db.Begin()
- if err != nil {
- beego.Error(err)
- }
-
- //查询预先定义的doctype流程类型
- dtID1, err := flow.DocTypes.GetByName("图纸设计")
- if err != nil {
- beego.Error(err)
- }
- beego.Info(dtID1)
- //查询预先定义的docstate状态1
- dsID1, err := flow.DocStates.GetByName("设计中...")
- if err != nil {
- fmt.Println(err)
- }
- beego.Info(dsID1)
- //查询预先定义的docstate状态2
- dsID2, err := flow.DocStates.GetByName("校核中...")
- if err != nil {
- fmt.Println(err)
- }
- beego.Info(dsID2)
- //查询预先定义的docstate状态3
- dsID3, err := flow.DocStates.GetByName("审查中...")
- if err != nil {
- fmt.Println(err)
- }
- beego.Info(dsID3)
- //查询预先定义的action动作1
- daID1, err := flow.DocActions.GetByName("提交设计")
- if err != nil {
- fmt.Println(err)
- }
- beego.Info(daID1)
- //查询预先定义的action动作2
- daID2, err := flow.DocActions.GetByName("校核") //应该叫"提交校核"
- if err != nil {
- fmt.Println(err)
- }
- beego.Info(daID2)
- //查询预先定义的action动作3
- daID3, err := flow.DocActions.GetByName("审查") //应该叫"提交审查"
- if err != nil {
- fmt.Println(err)
- }
- beego.Info(daID3)
- //查询预先定义的流程类型workflow,这个相当于doctype下面再分很多种流程
- //比如doctype为图纸设计流程,下面可以分为二级校审流程,三级校审流程,四级校审流程
- myWorkflow, err := flow.Workflows.GetByName("图纸设计-三级校审流程")
- if err != nil {
- beego.Error(err)
- }
- beego.Info(myWorkflow)
- //查询context——这个应该是管理用户-组-权限的
- accessContextID1, err := flow.AccessContexts.List("Context", 0, 0)
- if err != nil {
- beego.Error(err)
- }
- beego.Info(accessContextID1[0].ID)
-
- beego.Info(flow.GroupID(1))
- //开始为具体一个文件设立流程-此处是新建一个文件。对于旧文件应该怎么操作来着?
- docNewInput := flow.DocumentsNewInput{
- DocTypeID: dtID1.ID, //属于图纸设计类型的流程
- AccessContextID: accessContextID1[0].ID, //所有用户权限符合这个contex的要求
- GroupID: 11, //groupId,初始状态下的用户组,必须是个人用户组(一个用户也可以成为一个独特的组,因为用户无法赋予角色,所以必须将用户放到组里)
- Title: "厂房布置图", //这个文件的名称
- Data: "设计、制图: 秦晓川1, 校核: 秦晓川2", //文件的描述
- }
- // flow.Documents.New(tx, &docNewInput)
- DocumentID1, err := flow.Documents.New(tx, &docNewInput)
- if err != nil {
- beego.Error(err)
- }
- // tx.Commit() //new后面一定要跟commit
- beego.Info(DocumentID1)
-
- beego.Info(daID2)
- beego.Info(flow.GroupID(12))
-
- //针对具体一个文件定义动作事件,从"校核中……"状态通过动作"校核"将它修改为"审查中……"
- docEventInput := flow.DocEventsNewInput{
- DocTypeID: dtID1.ID, //flow.DocTypeID(1),
- DocumentID: DocumentID1,
- DocStateID: dsID1.ID, //document state must be this state,文档的现状状态
- DocActionID: daID2.ID, //flow.DocActionID(2),
- GroupID: 12, //必须是个人用户组
- Text: "校核",
- }
-
- docEventID1, err := flow.DocEvents.New(tx, &docEventInput)
- if err != nil {
- beego.Error(err)
- }
- tx.Commit() //一个函数里只能有一个commit,所以,这个是提前定义好的!!!!
- beego.Info(docEventID1)
- c.Data["json"] = "OK"
- c.ServeJSON()
- }
-
- // @Title post wf state
- // @Description post workflow state
- // @Success 200 {object} models.GetProductsPage
- // @Failure 400 Invalid page supplied
- // @Failure 404 data not found
- // @router /flownext [get]
- //对具体文件修改状态
- func (c *MainController) FlowNext() {
- //连接数据库
- driver, connStr := "mysql", "travis@/flow?charset=utf8&parseTime=true"
- tdb := fatal1(sql.Open(driver, connStr)).(*sql.DB)
- if tdb == nil {
- log.Fatal("given database handle is `nil`")
- }
- db := tdb
- tx, err := db.Begin()
- if err != nil {
- beego.Error(err)
- }
-
- myDocEvent, err := flow.DocEvents.Get(16)
- if err != nil {
- beego.Error(err)
- }
- beego.Info(myDocEvent)
-
- //给出接受的组groupids
- groupIds := []flow.GroupID{flow.GroupID(13)}
- beego.Info(groupIds)
- //查询workflow
- myWorkflow, err := flow.Workflows.GetByName("图纸设计-三级校审流程")
- if err != nil {
- beego.Error(err)
- }
- beego.Info(myWorkflow)
- newDocStateId, err := myWorkflow.ApplyEvent(tx, myDocEvent, groupIds)
- if err != nil {
- beego.Error(err)
- }
- tx.Commit() //一个函数里只能有一个commit!!!!
- fmt.Println("newDocStateId=", newDocStateId, err)
-
- c.Data["json"] = "OK"
- c.ServeJSON()
- }
-
- // beego.Info(wflist)
-
- // wflist, err = flow.DocStates.List(0, 0)
- // if err != nil {
- // beego.Error(err)
- // }
- // // beego.Info(wflist1)
- // wflist, err = DocActions.List(0, 0)
- // if err != nil {
- // beego.Error(err)
- // }
- // wflist1, err = flow.Workflows.List(0, 0)
- // if err != nil {
- // beego.Error(err)
- // }
- // fatal1 expects a value and an error value as its arguments.
- func fatal1(val1 interface{}, err error) interface{} {
- if err != nil {
- fmt.Println("%v", err)
- }
- return val1
- }
-
- // error0 expects only an error value as its argument.
- func error0(err error) error {
- if err != nil {
- fmt.Println("%v", err)
- }
- return err
- }
-
- // error1 expects a value and an error value as its arguments.
- func error1(val1 interface{}, err error) interface{} {
- if err != nil {
- fmt.Println("%v", err)
- return nil
- }
- return val1
- }
-
- // fatal0 expects only an error value as its argument.
- func fatal0(err error) {
- if err != nil {
- fmt.Println("%v", err)
- }
- }
安装mysql
建立flow数据库的用户:
CREATE USER 'travis'@'localhost' IDENTIFIED BY '';
在Navicat里新建一个flow数据库,选择utf8mb4——它源码里有个地方交代了。
开始数据库里的表下面是没有内容的,与下图不同。
然后给用户travis赋权。
必须将setup_db.sh文件拷贝到sql文件夹上一级,否则会出现下列错误:
将sql文件里的setup_db.sh和setup_blob_dirs.sh拷贝到上一级目录里(flow文件夹里),然后cmd窗口进入这个文件夹,运行
setup_db.sh -t
setup_blob_dirs.sh
go test
Flow里的sql语句是mysql的,和sqlite差别很大。从数据表初始化的sh文件开始就不同,一直到flow的go文件里的数据表插入数据,查询数据,jion连接表格,unique多列集合的约束,枚举数据类型,生成view数据表视图等等,太多的不同了。
在sqlite里,新建表用sh文件,也可以用改造好的beego自动建表,
- package models
-
- import (
- "fmt"
- "github.com/astaxie/beego/orm"
- "time"
- )
-
- // CREATE TABLE users_master (
- // id INT NOT NULL AUTO_INCREMENT,
- // first_name VARCHAR(30) NOT NULL,
- // last_name VARCHAR(30) NOT NULL,
- // email VARCHAR(100) NOT NULL,
- // active TINYINT(1) NOT NULL,
- // PRIMARY KEY (id),
- // UNIQUE (email)
- // );
- type users_master struct {
- Id int64
- First_name string `orm:"size(30)"`
- Last_name string `orm:"size(30)"`
- Email string `orm:"unique;size(100)"`
- Active bool
- }
-
- // CREATE TABLE wf_ac_group_hierarchy (
- // id INT NOT NULL AUTO_INCREMENT,
- // ac_id INT NOT NULL,
- // group_id INT NOT NULL,
- // reports_to INT NOT NULL,
- // PRIMARY KEY (id),
- // FOREIGN KEY (ac_id) REFERENCES wf_access_contexts(id),
- // FOREIGN KEY (group_id) REFERENCES wf_groups_master(id),
- // FOREIGN KEY (reports_to) REFERENCES wf_groups_master(id),
- // UNIQUE (ac_id, group_id)
- // );
- type wf_ac_group_hierarchy struct {
- Id int64
- Ac *wf_access_contexts `orm:"rel(fk);unique"`
- Group *wf_groups_master `orm:"rel(fk);unique"`
- Reports_to *wf_groups_master `orm:"rel(fk);column(reports_to)"`
- }
-
- // CREATE TABLE wf_ac_group_roles (
- // id INT NOT NULL AUTO_INCREMENT,
- // ac_id INT NOT NULL,
- // group_id INT NOT NULL,
- // role_id INT NOT NULL,
- // PRIMARY KEY (id),
- // FOREIGN KEY (ac_id) REFERENCES wf_access_contexts(id),
- // FOREIGN KEY (group_id) REFERENCES wf_groups_master(id),
- // FOREIGN KEY (role_id) REFERENCES wf_roles_master(id)
- // );
- type wf_ac_group_roles struct {
- Id int64
- Ac *wf_access_contexts `orm:"rel(fk)"`
- Group *wf_groups_master `orm:"rel(fk)"`
- Role *wf_roles_master `orm:"rel(fk)"`
- }
-
- ……
-
- ……
-
- // CREATE TABLE wf_workflows (
- // id INT NOT NULL AUTO_INCREMENT,
- // name VARCHAR(100) NOT NULL,
- // doctype_id INT NOT NULL,
- // docstate_id INT NOT NULL,
- // active TINYINT(1) NOT NULL,
- // PRIMARY KEY (id),
- // FOREIGN KEY (doctype_id) REFERENCES wf_doctypes_master(id),
- // FOREIGN KEY (docstate_id) REFERENCES wf_docstates_master(id),
- // UNIQUE (name),
- // UNIQUE (doctype_id)
- // );
- type wf_workflows struct {
- Id int64
- Name string `orm:"size(100);unique"`
- Doctype *wf_doctypes_master `orm:"rel(fk);unique"`
- Docstate *wf_docstates_master `orm:"rel(fk)"`
- Active bool
- }
-
- func init() {
- orm.RegisterModel(new(users_master), new(wf_ac_group_hierarchy), new(wf_ac_group_roles))
- orm.RegisterModel(new(wf_access_contexts), new(wf_docactions_master), new(wf_docevent_application))
- orm.RegisterModel(new(wf_docevents), new(wf_docstate_transitions), new(wf_docstates_master))
- orm.RegisterModel(new(wf_doctypes_master), new(wf_document_blobs), new(wf_document_tags))
- orm.RegisterModel(new(wf_group_users), new(wf_groups_master), new(wf_mailboxes))
- orm.RegisterModel(new(wf_messages), new(wf_role_docactions), new(wf_roles_master))
- orm.RegisterModel(new(wf_workflow_nodes), new(wf_workflows))
- }
-
- func InitFlow() {
- sql := fmt.Sprintf("CREATE VIEW wf_ac_perms_v AS " +
- "SELECT wf_ac_group_roles.ac_id, wf_ac_group_roles.group_id, wf_group_users.user_id, wf_ac_group_roles.role_id, wf_role_docactions.doctype_id, wf_role_docactions.docaction_id " +
- "FROM wf_ac_group_roles " +
- "JOIN wf_group_users ON wf_ac_group_roles.group_id = wf_group_users.group_id " +
- "JOIN wf_role_docactions ON wf_ac_group_roles.role_id = wf_role_docactions.role_id;")
-
- sql2 := fmt.Sprintf("INSERT INTO wf_docstates_master(name) VALUES('__RESERVED_CHILD_STATE__');")
-
- sql3 := fmt.Sprintf("INSERT INTO wf_roles_master(name) VALUES('SUPER_ADMIN');")
-
- sql4 := fmt.Sprintf("INSERT INTO wf_roles_master(name) VALUES('ADMIN');")
-
- sql5 := fmt.Sprintf("CREATE VIEW wf_users_master AS SELECT id, first_name, last_name, email, active FROM users_master;")
-
- o := orm.NewOrm()
- res, err := o.Raw(sql).Exec()
- if err == nil {
- num, _ := res.RowsAffected()
- fmt.Println("mysql row affected nums: ", num)
- } else {
- o.Rollback() // beego.Info("插入t_studentInfo表出错,事务回滚")
- }
- res, err = o.Raw(sql2).Exec()
- if err == nil {
- num, _ := res.RowsAffected()
- fmt.Println("mysql row affected nums: ", num)
- } else {
- o.Rollback() // beego.Info("插入t_studentInfo表出错,事务回滚")
- }
- res, err = o.Raw(sql3).Exec()
- if err == nil {
- num, _ := res.RowsAffected()
- fmt.Println("mysql row affected nums: ", num)
- } else {
- o.Rollback() // beego.Info("插入t_studentInfo表出错,事务回滚")
- }
- res, err = o.Raw(sql4).Exec()
- if err == nil {
- num, _ := res.RowsAffected()
- fmt.Println("mysql row affected nums: ", num)
- } else {
- o.Rollback() // beego.Info("插入t_studentInfo表出错,事务回滚")
- }
- res, err = o.Raw(sql5).Exec()
- if err == nil {
- num, _ := res.RowsAffected()
- fmt.Println("mysql row affected nums: ", num)
- } else {
- o.Rollback() // beego.Info("插入t_studentInfo表出错,事务回滚")
- }
- }
解决golang:unsupported Scan, storing driver.Value type []uint8 into type *time.Time
https://blog.csdn.net/han0373/article/details/81698713
在open连接后拼接参数:parseTime=true 即可
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。