浅析郭婶儿子--LitePal框架(二)

先膜拜一下郭神,话说郭神可以带我飞不?


1.上回说到context,这回我们接着说,配置完AndroidManifest.xml,下面就要开始建表了,bean中的内容又是如何跟数据库关联起来的呢?上篇博客说到郭哥使用SAX解析xml,其中SAX解析的格式是不变的,主要区别在handle,我们继续看handle的处理代码:

@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes)
			throws SAXException {
		if (LitePalParser.NODE_DB_NAME.equalsIgnoreCase(localName)) {
			for (int i = 0; i < attributes.getLength(); i++) {
				if (LitePalParser.ATTR_VALUE.equalsIgnoreCase(attributes.getLocalName(i))) {
					litePalAttr.setDbName(attributes.getValue(i).trim());
				}
			}
		} else if (LitePalParser.NODE_VERSION.equalsIgnoreCase(localName)) {
			for (int i = 0; i < attributes.getLength(); i++) {
				if (LitePalParser.ATTR_VALUE.equalsIgnoreCase(attributes.getLocalName(i))) {
					litePalAttr.setVersion(Integer.parseInt(attributes.getValue(i).trim()));
				}
			}
		} else if (LitePalParser.NODE_MAPPING.equalsIgnoreCase(localName)) {
			for (int i = 0; i < attributes.getLength(); i++) {
				if (LitePalParser.ATTR_CLASS.equalsIgnoreCase(attributes.getLocalName(i))) {
					litePalAttr.addClassName(attributes.getValue(i).trim());
				}
			}
		} else if (LitePalParser.NODE_CASES.equalsIgnoreCase(localName)) {
			for (int i = 0; i < attributes.getLength(); i++) {
				if (LitePalParser.ATTR_VALUE.equalsIgnoreCase(attributes.getLocalName(i))) {
					litePalAttr.setCases(attributes.getValue(i).trim());
				}
			}
		}
	}

首先获得数据库名,放到litePalAttrDBName,同理visioncase也一样,这里的class时间bean中是实体了.

/**
	 * Add a class name into the current mapping model list.
	 * 
	 * @param className
	 *            Full package class name.
	 */
	void addClassName(String className) {
		getClassNames().add(className);
	}

获得实体的属性值加入到className

public List<String> getClassNames() {
		if (classNames == null) {
			classNames = new ArrayList<String>();
			classNames.add("org.litepal.model.Table_Schema");
		} else if (classNames.isEmpty()) {
			classNames.add("org.litepal.model.Table_Schema");
		}
		return classNames;
	}

这里实体与数据库如何关联的差不多就明确了,主要还是SAX解析XML,给对应的属性赋值,上篇博客有提到是否可以建多个数据库,理论上是可以的,但是现在的版本暂时不支持,他没有对lite标签进行区分.估计郭哥以后的版本会添加这个功能!


2.说到数据库升级,郭神真是太屌了,改一个数据全搞定,这也体现了LitePal的巧妙之处,个人猜测郭神是根据version值的大小进行更新,旧版本号小于新版本号时更新,这只是个人猜测,还是去看一看郭哥的源码比较靠谱

@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		Generator.upgrade(db);
		SharedUtil.updateVersion(newVersion);
	}

首先郭哥继承了SQLiteOpenHelper,重写了onCreate方法和onUpgrade方法,这里不多说,继续看onUpgrade里面的实现方法

static void upgrade(SQLiteDatabase db) {
		drop(db);
		create(db, false);
		updateAssociations(db);
		upgradeTables(db);
		addAssociation(db, false);
	}

这里简单说一下,欲知详情,请看郭哥源码

1.删除数据库

2.创建数据库

3.更新数据库表,移除外键和中间链表

4.更新所有的数据库中的表

5.添加关联

更新完表之后,继续更新版本号

public static void updateVersion(int newVersion) {
		SharedPreferences.Editor sEditor = LitePalApplication.getContext()
				.getSharedPreferences(LITEPAL_PREPS, Context.MODE_PRIVATE).edit();
		sEditor.putInt(VERSION, newVersion);
		sEditor.commit();
	}

郭哥这里使用SharedPreferences直接把版本号存在了本地

 

3.LitePal存储数据

 郭哥说:LitePal进行表管理操作时不需要这些实体类有任何的继承结构,当时为了简单起见就没有写。但是进行CRUD操作时就不行了,LitePal要求所有的实体类都要继承自DataSupport这个类,因此这里我们就要把继承结构给加上才行。DataSupport主要是数据库和实体类的桥梁,郭哥在DataSupport中给出了一个实例:

* public class Person extends DataSupport {
 * 	private int id;
 * 	private String name;
 * 	private int age;
 * }

实体类Person会自动去映射person表,就相当于:

* CREATE TABLE person (
 * 	id integer primary key autoincrement,
 * 	age integer, 
 * 	name text
 * );

LitePal的保存主要是通过save()方法实现,当然save()方法里面调用了saveThrows(),你也可以直接调用saveThrows();下面看一下save()的源码:

public synchronized boolean save() {
		try {
			saveThrows();
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

这里调用saveThrows()主要就是返回成功与否了,没什么要解释的,那就直接看saveThrows()!

public synchronized void saveThrows() {
		SQLiteDatabase db = Connector.getDatabase();
		db.beginTransaction();
		try {
			SaveHandler saveHandler = new SaveHandler(db);
			saveHandler.onSave(this);
			clearAssociatedData();
			db.setTransactionSuccessful();
		} catch (Exception e) {
			throw new DataSupportException(e.getMessage());
		} finally {
			db.endTransaction();
		}
	}

1.创建表

2.开启事务

3.调用SaveHandleonSave方法

void onSave(DataSupport baseObj) throws SecurityException, IllegalArgumentException,
			NoSuchMethodException, IllegalAccessException, InvocationTargetException {
		String className = baseObj.getClassName();
		List<Field> supportedFields = getSupportedFields(className);
		Collection<AssociationsInfo> associationInfos = getAssociationInfo(className);
		if (!baseObj.isSaved()) {
			analyzeAssociatedModels(baseObj, associationInfos);
			doSaveAction(baseObj, supportedFields);
			analyzeAssociatedModels(baseObj, associationInfos);
		} else {
			analyzeAssociatedModels(baseObj, associationInfos);
			doUpdateAction(baseObj, supportedFields);
		}
	}

这里就涉及到关联问题了,一对一,多对一,多对多,根据以前见得实体是否更改,如果更改了就保存,没有更改则只是更新就可以了.这里涉及到的关联关系省略,主要看一下doSaveAction和doUpdateAction

private void doSaveAction(DataSupport baseObj, List<Field> supportedFields)
			throws SecurityException, IllegalArgumentException, NoSuchMethodException,
			IllegalAccessException, InvocationTargetException {
		ContentValues values = new ContentValues();
		beforeSave(baseObj, supportedFields, values);
		long id = saving(baseObj, values);
		afterSave(baseObj, supportedFields, id);
	}

在存值之前先判断其中的值是否发生变化,然后执行saving方法,返回的是id,是不是觉得很眼熟,哈哈,没错,这里执行的插入操作

private long saving(DataSupport baseObj, ContentValues values) {
		return mDatabase.insert(baseObj.getTableName(), null, values);
	}

同样的,doUpdateAction和doSaveAction差不多,不在赘述,只贴一下更新时的最终操作:

private void updating(DataSupport baseObj, ContentValues values) {
		mDatabase.update(baseObj.getTableName(), values, "id = ?",
				new String[] { String.valueOf(baseObj.getBaseObjId()) });
	}
4.清除关联数据

5.关闭事务


今天就扯这么多,再膜拜一下大神!


欲知详情,请听下回讲述!



















  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
docker-compose 是 Docker 官方的一个用于定义和运行容器化应用的工具。它使用 YAML 文件来配置应用的服务、网络和卷等方面的设置。 当使用 docker-compose 部署 MySQL 时,可能会遇到无法访问 MySQL 的问题。出现这种情况一般有以下几个可能的原因: 1. 网络配置问题:docker-compose 在默认情况下会创建一个默认的网络,并将所有定义的服务连接到该网络。如果服务的网络配置不正确,可能导致无法访问 MySQL。可以通过检查网络配置或创建自定义网络来解决此问题。 2. 端口映射问题:MySQL 默认使用 3306 端口进行通信,但是在容器内部的端口与宿主机上的端口之间可能存在映射问题。可以通过检查端口映射配置或使用容器的 IP 地址来解决此问题。 3. 认证问题:MySQL 服务通常需要进行身份验证才能访问。在 docker-compose 文件中,可以通过设置环境变量来指定 MySQL 的用户名和密码。如果未正确设置这些环境变量,可能导致无法访问 MySQL。可以检查环境变量配置或者在容器内部手动配置用户名和密码来解决此问题。 4. 容器启动顺序问题:如果在 docker-compose 文件中定义了多个服务,并且它们之间有依赖关系,那么容器启动的顺序可能会影响 MySQL 的访问。可以通过在容器之间添加依赖或者设置延迟启动来解决此问题。 总结起来,当 docker-compose 部署的 MySQL 无法访问时,通常是由于网络配置、端口映射、认证配置或容器启动顺序等问题造成的。通过检查这些配置,并进行适当的调整或修复,通常可以解决无法访问 MySQL 的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值