博主新写的 Android SQL 轻量框架,使用起来超简单。
当前优点:
1.保留原生SQL所有的操作特性,当你想要扩展时可直接继承Hibernate类进行扩展。
2.无需任何SQL配置文件。
3.无需写任何SQL代码(当然也支持自己写SQL代码)。
4.超级轻量:无须继承或实现接口,可和其他SQL框架共存。
5.支持映射,超多的映射字段。
6.增删查改,用法超级简单。
当前核心功能:
1.支持自动构建数据库与所有表(采用映射的方式生成表)。
2.支持表的多重父类继承属性。
3.支持动态创建表。
4.封装有 增删查改 方法,也可使用 原生SQL 的增删查改。
5.支持 聚合函数。
6.支持同时创建多个数据库,在多数据库的情景下,创建表时还支持分库映射 。
7.支持表字段属性:修改字段名、设置不为空、设置限定值、设置字段长度、设置最大值、设置最小值、设置不被持久化、设置默认值
8.支持主键自增长,仅支持 int、long 类型主键
9.支持线程中创建数据库
10.支持事务,saveAll(),保存全部的方法默认使用事务
11.支持索引:唯一索引、单列索引、组合索引
12.支持数据库 接口请求模式
在使用GT库里封装的架构当然需要先依赖好GT库:
详细依赖教程请参看
我们先了解一下 Hibernate 数据库 的基本特性:
String、[] | 字符串类型 |
int、Integer、[] | 整数类型、数组 |
boolean、Boolean、[] | 布尔类型、数组 |
double、Double、[] | 浮点类型、数组 |
float、Float、[] | 浮点类型、数组 |
Time | 时间类型 |
Date | 日期类型 |
long、Long、[] | 长整型、数组 |
short、Short、[] | 短整型、数组 |
byte[] | 字节数组 |
Object | 实体类 |
List<?> | ? 可以是任何类型 |
Map<?> | ? 可以是任何类型 |
注意:实体类必须要有无参构造方法或不重写任何构造方法也可,主键目前版本暂时仅支持自增的只有整数类型 ,如果没有在实体类中表示主键,Hibernate 会自动生成一个主键,本数据库不需要任何配置。
了解 Hibernate 基本特性后,接下来我们来看看如果使用。
第一步:基本使用教程
第一步:写好实体类待注解映射成表
@GT.Hibernate.GT_Bean//标识待Hibernate扫描的持久化类
public class DemoBean {
@GT.Hibernate.GT_Key//主键标识,默认自增长,也可以使用 (setAutoincrement = false) 方法来设置是否自增长
public int demoId;
//默认会自动映射到表中(博主方便演示,故使用 public 字段修饰,具体可按你自己习惯来写 get set)
public String name;
public int age;
public boolean sex;
@GT.Hibernate.GT_Column(setNotInit = true)//标识不参与映射
private String notValue;
@Override
public String toString() {
return "DemoBean{" +
"demoId=" + demoId +
", name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
}
第二步:构建 Hibernate
public class MainActivity extends AppCompatActivity {
@GT.Hibernate.Build(setSqlName = "DemoSQL", setSqlVersion = 1)//使用注解来构建 Hibernate:需要绑定 Activity
private GT.Hibernate hibernate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GT.build(this);//绑定 Activity
//第二种构建 Hibernate 方法,无需绑定 Activity
// GT.Hibernate hibernate = new GT.Hibernate().initialize("SQLName", 1, "123456", null);
GT.log(hibernate.getSqlAllTableName());//获取 DemoSQL数据库所有表名称
GT.log(hibernate.getTableAllValue(DemoBean.class));//获取 DemoBean 表所有字段名称
}
}
效果图:
两种构建效果相同,然后就可以直接编译运行了,完结。
是不是觉得使用起来超级简单方便,别激动,还有更简单的糖豆呢
接下来我们来看看其他的简单操作
第二步:添加、删除、修改、表字段
添加:
第一步:添加新字段 newAddValue
@GT.Hibernate.GT_Bean
public class DemoBean {
@GT.Hibernate.GT_Key//主键标识,默认自增长,也可以使用 (setAutoincrement = false) 方法来设置是否自增长
public int demoId;
//默认会自动映射到表中(博主方便演示,故使用 public 字段修饰,具体可按你自己习惯来写 get set)
public String name;
public int age;
public boolean sex;
public String newAddValue;//新添加的字段
@GT.Hibernate.GT_Column(setNotInit = true)//标识不参与映射
private String notValue;
@Override
public String toString() {
return "DemoBean{" +
"demoId=" + demoId +
", name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
}
第二步:更新数据库 setSqlVersion +1
public class MainActivity extends AppCompatActivity {
@GT.Hibernate.Build(setSqlName = "DemoSQL", setSqlVersion = 2)//sqlVersion + 1
private GT.Hibernate hibernate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GT.build(this);//绑定 Activity
GT.log(hibernate.getSqlAllTableName());//获取 DemoSQL数据库所有表名称
GT.log(hibernate.getTableAllValue(DemoBean.class));//获取 DemoBean 表所有字段名称
}
}
效果图:
删除:
第一步:删除旧字段 newAddValue
@GT.Hibernate.GT_Bean
public class DemoBean {
@GT.Hibernate.GT_Key//主键标识,默认自增长,也可以使用 (setAutoincrement = false) 方法来设置是否自增长
public int demoId;
//默认会自动映射到表中(博主方便演示,故使用 public 字段修饰,具体可按你自己习惯来写 get set)
public String name;
public int age;
public boolean sex;
// public String newAddValue;//删除的字段
@GT.Hibernate.GT_Column(setNotInit = true)//标识不参与映射
private String notValue;
@Override
public String toString() {
return "DemoBean{" +
"demoId=" + demoId +
", name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
}
第二步:更新数据库 setSqlVersion +1
public class MainActivity extends AppCompatActivity {
@GT.Hibernate.Build(setSqlName = "DemoSQL", setSqlVersion = 3)//sqlVersion + 1
private GT.Hibernate hibernate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GT.build(this);//绑定 Activity
GT.log(hibernate.getSqlAllTableName());//获取 DemoSQL数据库所有表名称
GT.log(hibernate.getTableAllValue(DemoBean.class));//获取 DemoBean 表所有字段名称
}
}
效果图:
修改:修改字段时,如果该表字段下有数据,会保留在新字段里
第一步:将 name 修改为 myName
@GT.Hibernate.GT_Bean
public class DemoBean {
@GT.Hibernate.GT_Key//主键标识,默认自增长,也可以使用 (setAutoincrement = false) 方法来设置是否自增长
public int demoId;
@GT.Hibernate.GT_Column(setOldTableValue = "name")//将旧表的字段名称写在这里
public String myName;//新修改的字段名
public int age;
public boolean sex;
@GT.Hibernate.GT_Column(setNotInit = true)//标识不参与映射
private String notValue;
@Override
public String toString() {
return "DemoBean{" +
"demoId=" + demoId +
", myName='" + myName + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
}
第二步:更新数据库 setSqlVersion +1
public class MainActivity extends AppCompatActivity {
@GT.Hibernate.Build(setSqlName = "DemoSQL", setSqlVersion = 4)//sqlVersion + 1
private GT.Hibernate hibernate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GT.build(this);//绑定 Activity
GT.log(hibernate.getSqlAllTableName());//获取 DemoSQL数据库所有表名称
GT.log(hibernate.getTableAllValue(DemoBean.class));//获取 DemoBean 表所有字段名称
}
}
效果图:
你一行SQL语句都没写,有没有,干杯!接下来要上正菜了
第三步:增删查改-数据
插入数据
public class MainActivity extends AppCompatActivity {
@GT.Hibernate.Build(setSqlName = "DemoSQL", setSqlVersion = 4)//sqlVersion + 1
private GT.Hibernate hibernate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GT.build(this);//绑定 Activity
DemoBean demoBean = new DemoBean();
demoBean.myName = "小明";
demoBean.age = 9;
demoBean.sex = true;
hibernate.save(demoBean);//保存数据
//查询 DemoBean 表所有数据
for (DemoBean demoBean1 : hibernate.queryAll(DemoBean.class)) GT.log(demoBean1);
}
}
还可以一次性插入多条数据:
public class MainActivity extends AppCompatActivity {
@GT.Hibernate.Build(setSqlName = "DemoSQL", setSqlVersion = 4)//sqlVersion + 1
private GT.Hibernate hibernate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GT.build(this);//绑定 Activity
//模拟数据
List<DemoBean> demoBeanList = new ArrayList<>();
for (int i = 0; i < 9; i++) {
DemoBean demoBean = new DemoBean();
demoBean.myName = "小明";
demoBean.age = i;
demoBean.sex = i % 2 == 0;
demoBeanList.add(demoBean);//存储起来
}
hibernate.saveAll(demoBeanList);//插入多条数据
//查询 DemoBean 表所有数据
for (DemoBean demoBean1 : hibernate.queryAll(DemoBean.class)) GT.log(demoBean1);
}
}
参考图:
删除数据
//删除主键为 1的数据
hibernate.delete(DemoBean.class, 1);
//筛选条件删除
hibernate.where("myName = ?","小明").delete(DemoBean.class);
//指定两个条件筛选删除数据
hibernate.where(new String[]{"myName","age"},new String[]{"小明","1"})
.delete(DemoBean.class);
//删除所有 年龄大于3 的小明
hibernate.where("age > ?",3).deleteAll(DemoBean.class);
//清空 DemoBean 表数据
hibernate.deleteAll(DemoBean.class);
参考图:
查询数据
//查询 主键为4 的数据
DemoBean demoBean = hibernate.query(DemoBean.class, 4);
//查询 年龄为3 的数据
DemoBean demoBean = hibernate
.where("age = ?", "3")
.query(DemoBean.class);
//查询 名称 为小明且年龄是5 的数据
DemoBean demoBean = hibernate
.where(new String[]{"myName", "age"},
new String[]{"小明", "5"})
.query(DemoBean.class);
//查询 年龄大于5 的所有数据
List<DemoBean> demoBeanList = hibernate
.where("age > ?", 5)
.queryAll(DemoBean.class);
//查询 名字为小明且年龄大于2 的所有数据
List<DemoBean> demoBeanList = hibernate
.where("myName = ? and age > ?",
new String[]{"小明","2"})
.queryAll(DemoBean.class);
//查询 DemoBean表 所有数据
List<DemoBean> demoBeanList = hibernate.queryAll(DemoBean.class);
参考图:
修改数据
//将 主键为 1 的数据修改成以下数据
DemoBean demoBean = new DemoBean();
demoBean.demoId = 1;//关键
demoBean.myName = "小红";
demoBean.sex = false;
demoBean.age = 21;
hibernate.update(demoBean);
//查询 主键为 1 的数据 并修改主键为 1 的数据
DemoBean demoBean = hibernate.query(DemoBean.class, 1);
demoBean.myName = "大明";//将名字改为 大明
hibernate.update(demoBean);//开始修改数据库数据
/*将年龄 大于5 的数据 名称全部修改成 大明
注意:如果你的筛选条件只会有一个成立,那就只会修改这一条数据*/
ContentValues contentValues = new ContentValues();
contentValues.put("myName", "大明");
hibernate.where("age > ?", 5).update("DemoBean", contentValues);
//或
hibernate.where("age > ?", 5).updateAll(DemoBean.class, contentValues);
总结:是不是发现 where 语句用法其实都是一样的,只要你学会了where 那么就可以在 增删查改中呼风唤雨了。
小彩蛋:isStatus() 增删查改里的方法,均有支持使用这个方法。
boolean status = hibernate.save(demoBean).isStatus();
if(status){
//保存成功
}else{
//保存失败
}
学会了以上内容其实也足以应对基础的数据库SQL功能了,但下面要介绍的就是更加高级的功能了,博主写的博客不是让你全部记住哦,忘记了再回来看看,记得关注收藏
第四步:Hibernate 高级用法
第一个:事务的使用
//开启事务
hibernate.beginTransaction();
//进行多种数据库操作,如果其中有一个操作失败,那么本次已操作的动作都会回滚到最原始状态
hibernate.update(demoBean);
for(DemoBean demoBean : hibernate.queryAll(DemoBean.class)){
demoBean.myName = "超大明";
hibernate.update(demoBean);
}
hibernate.delete(DemoBean.class,2);
//结束事务
hibernate.endTransaction();
第二个:聚合函数
//返回表中有多少条数据
long count = hibernate.count(DemoBean.class);
//求当前列的总和
Object ageSum = hibernate.sum(DemoBean.class, "age");
//求当前列最大值
Object ageMax = hibernate.max(DemoBean.class, "age");
//求当前列最小值
Object ageMin = hibernate.min(DemoBean.class, "age");
//求平均数
Object age = hibernate.average(DemoBean.class, "age");
第三个:分库映射
分库映射适用于应付较为复杂的SQL应用场景,GT库提供了非常灵活的分库映射方法
在调试阶段如已有该数据库,请删除数据库文件后再调试
我们先来创建一个非常简单的示例:
第一步:先创建两个实体类
@GT.Hibernate.GT_Bean //没有指定任何映射的库
public class DemoBean {
@GT.Hibernate.GT_Key//主键标识,默认自增长
public int demoId;
public String name;//普通表字段
}
@GT.Hibernate.GT_Bean //没有指定任何映射的库
public class GSLSBean {
@GT.Hibernate.GT_Key//主键标识,默认自增长
public int gId;
public int age;//普通表字段
}
第二步:创建两个数据库
public class MainActivity extends AppCompatActivity {
@GT.Hibernate.Build(setSqlName = "hibernate1", setSqlVersion = 1) //创建第一个数据库
private GT.Hibernate hibernate1;
@GT.Hibernate.Build(setSqlName = "hibernate2", setSqlVersion = 1) //创建第二个数据库
private GT.Hibernate hibernate2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GT.build(this);//绑定 Activity
//两个数据库 分别获取当前已映射成功的表
GT.log("hibernate1:", hibernate1.getSqlAllTableName());
GT.log("hibernate2:", hibernate2.getSqlAllTableName());
}
}
效果图:
从日志我们不难看出,数据库 hibernate1、hibernate2 分别都将 两个表都映射到数据库中了,那我们从此就可以看出,若你的 表没有指定数据库 或 数据库没有指定映射的表 那该数据库将默认映射所有能映射的表。
接下来我们来看看 表怎么指定数据库:
@GT.Hibernate.GT_Bean(setSqlNames = "hibernate1")//指定扫描的数据库,未指定的数据库默认不映射该表表
public class GSLSBean {
@GT.Hibernate.GT_Key//主键标识,默认自增长
public int gId;
public int age;//普通表字段
}
在表注解后面添加括号,在括号里设置指定扫描的数据库
日志效果图:
这时就会神奇的发现, 数据库2 默认只能扫描到DemoBean表
但一个表想要指定多个数据库时,可以这样设置:
@GT.Hibernate.GT_Bean(setSqlNames = {"hibernate1","hibernate2"})//指定扫描的数据库,未指定的数据库默认不映射该表
public class GSLSBean {
@GT.Hibernate.GT_Key//主键标识,默认自增长
public int gId;
public int age;//普通表字段
}
好了,看完表指定数据库,我们再来看看数据库如何指定映射的表
表指定数据库:
第一步:先将刚才改动的 表指定数据的所有都回复到原始状态:
第二步:让数据库来指定映射的表:在调试阶段如已有该数据库,请删除数据库文件后再调试
public class MainActivity extends AppCompatActivity {
//指定该数据库只映射 DemoBean 表
@GT.Hibernate.Build(setSqlName = "hibernate1", setSqlVersion = 1, setSqlTables = DemoBean.class)
private GT.Hibernate hibernate1; //创建第一个数据库
//若不指定,则默认映射所有 标有 @GT.Hibernate.GT_Bean 的实体类,映射成表
@GT.Hibernate.Build(setSqlName = "hibernate2", setSqlVersion = 1)
private GT.Hibernate hibernate2;//创建第二个数据库
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GT.build(this);//绑定 Activity
//两个数据库 分别获取当前已映射成功的表
GT.log("hibernate1:", hibernate1.getSqlAllTableName());
GT.log("hibernate2:", hibernate2.getSqlAllTableName());
}
}
日志效果图:
数据库映射多表可以这样设置:
public class MainActivity extends AppCompatActivity {
//指定该数据库只映射 DemoBean 表
@GT.Hibernate.Build(setSqlName = "hibernate1", setSqlVersion = 1, setSqlTables = {DemoBean.class, GSLSBean.class})
private GT.Hibernate hibernate1; //创建第一个数据库
//若不指定,则默认映射所有 标有 @GT.Hibernate.GT_Bean 的实体类,映射成表
@GT.Hibernate.Build(setSqlName = "hibernate2", setSqlVersion = 1, setSqlTables = GSLSBean.class)
private GT.Hibernate hibernate2;//创建第二个数据库
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GT.build(this);//绑定 Activity
//两个数据库 分别获取当前已映射成功的表
GT.log("hibernate1:", hibernate1.getSqlAllTableName());
GT.log("hibernate2:", hibernate2.getSqlAllTableName());
}
}
日志效果图:
总结:给一个小糖果给你,GT里所有注解上要设置参数的话,指甲在括号里输入 set 即可出现所有的参数提示
第五个:线程构建数据库
应用场景:
当你的数据表比较多,且比较复杂字段较多时,在映射时会相对耗一些时间,少的100毫秒多则600毫秒不等,具体耗时多长主要看设备配置的高低和表多少、表的复杂度有关,这时就可以使用GT自带的线程方式来构建数据库,对于APP来说那就是耗时几乎为0毫秒
public class MainActivity extends AppCompatActivity {
//指定该数据库使用线程的方法来构建
@GT.Hibernate.Build(setSqlName = "hibernate1", setSqlVersion = 1, setIsThread = true)
private GT.Hibernate hibernate1; //创建第一个数据库
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GT.build(this);//绑定 Activity
//如果使用了线程构建,切记不要直接使用,需要在单击事件或者延时函数里使用
if(hibernate1.getSqliteDatabase() != null){// 标准使用:使用前需要判断 SqliteDatabase 是否为空
hibernate1.getSqlAllTableName();
}
}
}
第六个:创建索引
第七个:采用接口方式管理数据库
public interface DaoAPI {
//插入操作
@GT.Hibernate.GT_Insert
GT.Hibernate.Call<UserBean> insert(UserBean userBean);
//插入多个操作
@GT.Hibernate.GT_Insert
GT.Hibernate.Call<UserBean[]> inserts(UserBean... userBeans);
//插入所有操作
@GT.Hibernate.GT_Insert
GT.Hibernate.Call<List<UserBean>> insertAll(List<UserBean> list);
//删除操作(注意:条件值名称一定要按顺序对齐)
@GT.Hibernate.GT_Delete(where = "name = ? and age = ?")
GT.Hibernate.Call<UserBean> delete(String name, int age);
@GT.Hibernate.GT_Delete(where = "userId = ?")
GT.Hibernate.Call<UserBean> delete(int userId);
//删除的条件同上一样,通过 实体类中的ID判定删除
@GT.Hibernate.GT_Delete
GT.Hibernate.Call<UserBean> delete(UserBean userBean);
@GT.Hibernate.GT_Delete
GT.Hibernate.Call<UserBean> deleteAll();
//查询操作(注意:条件值名称一定要按顺序对齐)
@GT.Hibernate.GT_Query(where = "userId = ? ")
GT.Hibernate.Call<UserBean> query(int userId);
@GT.Hibernate.GT_Query(where = "sex = ? and age = ?")
GT.Hibernate.Call<UserBean> query(String sex, int age);
//查询数据 根据 WhereBean 类中的条件信息,来查询
@GT.Hibernate.GT_Query
GT.Hibernate.Call<UserBean> query(GT.Hibernate.WhereBean whereBean);
//查询所有,返回值为 List 默认识别为 查询所有
@GT.Hibernate.GT_Query
GT.Hibernate.Call<List<UserBean>> queryAll();
//查询所有 并加入条件值
@GT.Hibernate.GT_Query(where = "sex = ? and age > ?")
GT.Hibernate.Call<List<UserBean>> queryAll(String sex, int age);
//修改操作(注意:条件值名称一定要按顺序对齐)
@GT.Hibernate.GT_Update(where = "age = ?")
GT.Hibernate.Call<UserBean> update(int age, ContentValues contentValues);
@GT.Hibernate.GT_Update
GT.Hibernate.Call<UserBean> update(UserBean userBean);
//自定义 SQL 代码操作,?问号 的顺序必须对应 形参的顺序
@GT.Hibernate.GT_Code("SELECT name, age FROM UserBean WHERE name LIKE '%?%'")
GT.Hibernate.Call<List<UserBean>> query(String name);
@GT.Hibernate.GT_Code("DELETE FROM UserBean WHERE name = '?'")
GT.Hibernate.Call<UserBean> delete(String name);
@GT.Hibernate.GT_Code("UPDATE UserBean SET name = '?' ,age = ?, sex = '?' WHERE userId = ?")
GT.Hibernate.Call<UserBean> update(String name, int age, String sex, int userId);
@GT.Hibernate.GT_Code("INSERT INTO UserBean VALUES (?, ?, '?', '?')")
GT.Hibernate.Call<List<UserBean>> save(int userId, int age, String name, String sex);
}
接口模式的使用:
@GT.Annotations.GT_AnnotationActivity(R.layout.activity_main)
public class MainActivity extends GT.GT_Activity.AnnotationActivity {
@GT.Hibernate.Build(setSqlVersion = 1)
private static GT.Hibernate hibernate;
protected void initView(Bundle savedInstanceState) {
super.initView(savedInstanceState);
//创建 接口引用,需要传入 hibernate 引用
DaoAPI daoAPI = GT.Hibernate.create(DaoAPI.class, hibernate);
//异步查询数据库
daoAPI.query("男",2).newCall(new GT.Hibernate.Callback<UserBean>() {
@Override
public void onSuccess(UserBean userBean, GT.Hibernate.Call<UserBean> call) {
super.onSuccess(userBean, call);
GT.logt("查询成功:" + userBean);
}
@Override
public void onError(GT.Hibernate.Call<UserBean> call, Exception e) {
super.onError(call, e);
GT.logt("查询失败:" + call);
}
});
}
}
第八个:功能方法
1.获取 数据库 SQLiteDatabase对象
//获取 数据库 SQLiteDatabase对象
SQLiteDatabase sqLiteDatabase = hibernate.getSqLiteDatabase();
2.删除整张表
//删除整个表
hibernate.deleteTable("LoginBean");
3.获取当前表所有字段
//获取当前表所有字段
List<String> loginBeanAllValue = hibernate.getTableAllValue("LoginBean");
4.1迁移表数据
//迁移表数据
hibernate.inputTableData("旧表名称","新表名称");
4.2迁移表数据
//迁移表数据
List<String> oldList = new ArrayList<>();//指定旧表迁移的数据
List<String> newList = new ArrayList<>();//指定新表迁移的数据
hibernate.inputTableData("旧表名称",oldList,"新表名称",newList);
5.当前表是否存在
//当前表是否存在
boolean loginBeanTF = hibernate.isTable("LoginBean");
6.更改表名
//更改表名
hibernate.updateTableName("旧表名称","新表名称");
总结:GT Hibernate 的数据库操作的学习算是告一段落了,今后还会继续维护该数据库。感谢各位朋友的关注。
欢迎各位朋友在文章中提出自己宝贵的建议。