publicUnitOfWork( ISqlSugarClient sqlSugarClient){_sqlSugarClient = sqlSugarClient;}
//获取DB,保证唯一性//publicSqlSugarClient GetDbClient( ){// 必须要as,后边会用到切换数据库操作return_sqlSugarClient asSqlSugarClient;}
publicvoidBeginTran( ){GetDbClient.BeginTran;}
publicvoidCommitTran( ){try{GetDbClient.CommitTran; //}catch(Exception ex){GetDbClient.RollbackTran;throwex;}}
publicvoidRollbackTran( ){GetDbClient.RollbackTran;}
}
如果修改好了,工作单元,记得也要修改要工作单元接口。
4
动态获取 _db 实例
在上边,我们在工作单元uow(unitOfWork)中,注入了数据库实例,那现在就要获取这个实例了,很简单,直接基类仓储BaseRepository.cs构造函数中,依赖注入我们的IUnitOfWork接口:
privateSqlSugarClient _dbBase;publicBaseRepository(IUnitOfWork unitOfWork){_unitOfWork= unitOfWork;_dbBase= unitOfWork.GetDbClient;}
获取到这个 _dbBase 以后,其实这个时候已经可以了,我们就可以任意的使用这个db实例,但是我们今天的目的是要动态切换,重头戏来了,既然我们每次请求都需要这个db,那简单,我们就修改它的属性:
privateISqlSugarClient _db{get{/* 如果要开启多库支持,* 1、在appsettings.json 中开启MutiDBEnabled节点为true,必填* 2、设置一个主连接的数据库ID,MainDB,必填*/if(Appsettings.app( newstring[] { "MutiDBEnabled"}).ObjToBool){// 默认会获取当前Model的特性,看看是否配置了连接db的ConnIDif( typeof(TEntity).GetTypeInfo.GetCustomAttributes( typeof(SugarTable), true).FirstOrDefault(( x=>x.GetType == typeof(SugarTable))) is SugarTable sugarTable){_dbBase.ChangeDatabase(sugarTable.TableDeion.ToLower);}else{// 如果不存在,则表明当前Model是主数据库操作// 这个配置的地点,看文章上边第二节,注入服务的时候_dbBase.ChangeDatabase(MainDb.CurrentDbConnId.ToLower);}}return_dbBase;}}
5
实体类和连接字符串的配置
首先呢,我们需要在appsettings.json中,配置多个库的连接字符串,注意,如果想要打开多个,就要把那几个的Enabled全部设置为true:
"MainDB": "WMBLOG_SQLITE", // 当前主库的连接字符串,不填写的话,默认是下边true的第一个"MutiDBEnabled": false, // 是否开启多库,默认是false"DBS": [/*MySql = 0,SqlServer = 1,Sqlite = 2,Oracle = 3,PostgreSQL = 4*/{"ConnId": "WMBLOG_SQLITE","DBType": 2,"Enabled": true,"Connection": "WMBlog.db"//只写数据库名就行,我会拼接字符串},{"ConnId": "WMBLOG_MSSQL","DBType": 1,"Enabled": true,"Connection": "Server=.;Database=WMBlogDB;User ID=sa;Password=123;","ProviderName": "System.Data.SqlClient"},{"ConnId": "WMBLOG_MYSQL","DBType": 0,"Enabled": false,"Connection": "Server=localhost; Port=3306;Stmt=; Database=wmblogdb; Uid=root; Pwd=456;"},{"ConnId": "WMBLOG_ORACLE","DBType": 3,"Enabled": false,"Connection": "Provider=OraOLEDB.Oracle; Data Source=WMBlogDB; User Id=sss; Password=789;","OracleConnection_other1": "User ID=sss;Password=789;Data Source=(DEION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.8.65)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME = orcl)))"}],
然后我们修改一下Model,配置SugarTable特性,第一个参数是表明,第二个是对应的db连接字符串的ConnID,这里我们用密码表做测试:
//密码库表///[ SugarTable( "PasswordLib", "WMBLOG_MSSQL")]publicclassPasswordLib{[ SugarColumn(IsNullable = false, IsPrimaryKey = true, IsIdentity = true)]publicintPLID { get; set; }}
到了这里,我们就可以随意的做多库操作了。
我们看看效果吧。
6
实现操作两个数据库效果
首先,开启多库配置:
我们测试两个数据库,一个是Sqlite主库,一个是Sqlserver从库,
从主库中,获取博客信息,从库中获取密码表信息,就是刚刚我们在上边配置的实体。
//测试多库连接//[ HttpGet( "TestMutiDBAPI")][ AllowAnonymous]publicasyncTask< object> TestMutiDBAPI( ){// 从主库(Sqlite)中,操作blogsvarblogs = await_blogArticleServices.Query(d => d.bID == 1);// 从从库(Sqlserver)中,获取pwdsvarpwds = await_passwordLibServices.Query(d => d.PLID > 0;
returnnew{blogs,pwds};}
为了做对比效果,我把这两个表,从数据库中删掉,也就是blog在从库中删掉,pwd在主库中删掉:
我们做一个动图,来看看效果:
尽管两个表在对方的数据库不存在,但是我们还是获取到了数据:
那是不是这样就高枕无忧了呢,别慌!咱们是事务不会被破坏吧!来再试试。
7
检验事务操作是否正常
项目中有一个测试接口,大概意思就是先读取一个表数据,然后添加一条数据,中间制造一个异常,最后做回滚操作,看看是否添加的数据被删掉。
[ HttpGet]publicasyncTask> Get{List< string> returnMsg = newList< string> { };try{returnMsg.Add( $"Begin Transaction");_unitOfWork.BeginTran;varpasswords = await_passwordLibServices.Query(d=>d.IsDeleted== false);returnMsg.Add( $"first time : the count of passwords is : {passwords.Count}");
returnMsg.Add( $"insert a data into the table PasswordLib now.");varinsertPassword = await_passwordLibServices.Add( newPasswordLib{IsDeleted = false,plAccountName = "aaa",plCreateTime = DateTime.Now});
passwords = await_passwordLibServices.Query(d => d.IsDeleted == false);returnMsg.Add( $"second time : the count of passwords is : {passwords.Count}");returnMsg.Add( $" ");
//......
varguestbooks = await_guestbookServices.Query;returnMsg.Add( $"first time : the count of guestbooks is : {guestbooks.Count}");
intex = 0;returnMsg.Add( $"There's an exception!!");returnMsg.Add( $" ");intthrowEx = 1/ ex;
varinsertGuestbook = await_guestbookServices.Add( newGuestbook{username = "bbb",blogId = 1,createdate = DateTime.Now,isshow = true});
guestbooks = await_guestbookServices.Query;returnMsg.Add( $"first time : the count of guestbooks is : {guestbooks.Count}");returnMsg.Add( $" ");
_unitOfWork.CommitTran;}catch(Exception){_unitOfWork.RollbackTran;varpasswords = await_passwordLibServices.Query;returnMsg.Add( $"third time : the count of passwords is : {passwords.Count}");
varguestbooks = await_guestbookServices.Query;returnMsg.Add( $"third time : the count of guestbooks is : {guestbooks.Count}");}
returnreturnMsg;}
动图太大,这么不放了,肯定是正确的,直接看结果吧:
打完收工!距离微服务又近了一步。
"
每一个努力的,或者正在努力的人,都应该值得被尊重。
——老张的哲学