jxTMS usage example -- database operation

Posted by claire on Sat, 22 Jan 2022 18:49:11 +0100

To use this example, you need to go through the docker container. Please drop down first docker image of jxTMS Start the tms container according to the instructions and helloWorld Start trying.

Database operation of jxTMS

For programming, database operations include:

  • Definition of data table

  • ORM [object relationship mapping] operation, that is, adding, deleting, modifying and querying

  • Condition query

Let's demonstrate how jxTMS operates the first two items. Please refer to the next section for condition query.

Definition of data table

jxTMS realizes the definition of data table by defining a data class in the data file under the function module directory. You can create a data file in the demo1 directory, and then enter:

class demoData:
	#jxTMS data objects must have a primary key to save. It is generally recommended to use a long ID as the primary key, otherwise various accidents may occur
	field ID long primaryKey
	field CreateTime datetime

	field Type string len=32 index 2
	field Name string len=126 fulltext
	
	field NoUsed bool
;

Then press the file Managing jxTMS code with sftp Copy the to the / home/tms/codeDefine/demo/demo/demo1 directory of the tms container.

Now you can view the database , see if there is a data table named demoData:

#Switch the target database to the organization's private database: Demo_ six thousand two hundred and eighty-eight
mysql> use demo_6288;
#View the description of the data table demoData
mysql> desc demoData;

Then execute once Hot engine refresh.

again view the database , see if there is a data table named demoData:

#Review the description of the data table demoData again
mysql> desc demoData;
+------------+--------------+------+-----+---------+-------+
| Field      | Type         | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| ID         | bigint(20)   | NO   | PRI | NULL    |       |
| NoUsed     | tinyint(4)   | NO   |     | NULL    |       |
| Type       | varchar(32)  | NO   | MUL | NULL    |       |
| CreateTime | datetime     | NO   |     | NULL    |       |
| Name       | varchar(126) | NO   | MUL | NULL    |       |
+------------+--------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

It can be seen that a data table of demoData automatically appears in the database corresponding to the demo organization, and the columns in the data correspond to our definitions in the data file one by one. Then let's look at the table creation statement of demoData:

mysql> show create table demoData;
| demoData | CREATE TABLE `demoData` (
  `ID` bigint(20) NOT NULL,
  `NoUsed` tinyint(4) NOT NULL,
  `Type` varchar(32) NOT NULL,
  `CreateTime` datetime NOT NULL,
  `Name` varchar(126) NOT NULL,
  PRIMARY KEY (`ID`),
  KEY `index_demoData_2` (`Type`),
  FULLTEXT KEY `index_demoData_F0` (`Name`) /*!50100 WITH PARSER `ngram` */ 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |

We can further see that the ID in the demoData table is the primary key, and in the definition of class demoData:

#The ID attribute has a primaryKey definition
field ID long primaryKey

An index is established by Type, and in the definition of class demoData:

#The Type attribute has a No. 2 index. Please note that the name of the relevant index of the database table is exactly: index_ demoData_ two
field Type string len=32 index 2

A full-text index is also established by Name, and in the definition of class demoData:

#The Name property has a full-text index
field Name string len=126 fulltext

Note 1: the minimum word segmentation unit of full-text index is two characters [support Chinese], so when using full-text index, you cannot only enter one character, but must be greater than or equal to two characters

Note 2: due to the limitation of mysql, only one full-text index can be used in a query statement. If there are more than two full-text indexes, nothing can be found

By comparing the definition of the demoData class in the data file and the output of the show create table demoData command, you can easily understand how to define a data table with the data file. For specific instructions, please refer to Custom data class.

ORM operation

Now we have defined the demoData data class through the data file, and jxTMS has automatically created the demoData data table for us. Let's try how to operate them.

Note: starting from this section, all of capa The modification of Py is to add or modify an object function in the definition of demo1 class. We must pay attention to the indentation of these functions so that they must be the object function of demo1

We modify capa Py to create a new demoData object [corresponding to a row in the demoData table]:

@myModule.event('cmd', 'sayHello')
def sayHello(self, db, ctx):
	dd = pyORM.create(db,'demoData')
	dd.Type = 'demo'
	dd.Name = 'Hello world!'

Then execute once Hot engine refresh.

Then click [Demo - > HelloWorld] in the shortcut bar and click [click me]. Then look at the demoData table:

mysql> select * from demoData;
+-----------------+--------+------+---------------------+--------------+
| ID              | NoUsed | Type | CreateTime          | Name         |
+-----------------+--------+------+---------------------+--------------+
| 103897269075998 |      0 | demo | 2021-06-11 07:00:30 | Hello world! |
+-----------------+--------+------+---------------------+--------------+
1 row in set (0.00 sec)

Note: ID and CreateTime will not be the same as in the demo

You will find that a row of data is indeed inserted, and the Type and Name are indeed specified in sayHello, but the ID and CreateTime are not specified? This is because jxTMS will default that if a data class has an ID and CreateTime defined, it will automatically initialize for us. The ID will be given a unique value, and CreateTime will be given the time value when the create function is called.

Note: ID generation depends on the host number and time. It supports 255 hosts and can generate 16M unique IDs every 1024 milliseconds

All data classes defined in the data file are pyORM classes, and then jxTMS virtualizes them as demoData according to the definition in the data file. However, developers do not need to care about this. As long as the class name of the defined data class is specified to the create function, jxTMS will automatically create a virtual data class, and then directly assign values to its attributes, jxTMS will translate these values into the corresponding database type and save them to the database.

Remember the ID value of dataData you found in the database [I found 103897269075998, you need to change it to yours], and then we modify CAPA again Py, add a prepareDisp response function of helloWorld interface:

#After the helloWorld interface is displayed, perform interface initialization for it
@myModule.event('prepareDisp', 'helloWorld')
def helloWorld(self, db, ctx):
	#Read the newly created data object
	#Please replace 103897269075998 with the ID value you query from the database
	dd = pyORM.getByID(db.get,'demoData',103897269075998)
	#Write information to the control bound with outText
	self.setOutput('outText',utils.getMsg('{}.{}/from:{}',dd.Type,dd.Name,dd.ID)

Then execute once Hot engine refresh After that, click [Demo - > HelloWorld] in the shortcut bar again to see how it is different from the previous one?

jxTMS can directly read the corresponding data row from the database through the getByID function, then create a virtual demoData object, and assign a value to the attribute with the same name of the object with the read data. Then you can directly use the attribute values of the object.

Now let's continue to modify the sayHello function:

@myModule.event('cmd', 'sayHello')
def sayHello(self, db, ctx):
	#Please replace 103897269075998 with the ID value you found in the database
	dd = pyORM.getByID(db.getDBConn(),'demoData',103897269075998)
	dd.Type = 'test'
	dd.Name = 'ok'
	db.update(dd,'Type','Name')

Then execute once Hot engine refresh.

Click [Demo - > HelloWorld] in the shortcut bar again and click [click me]. Then view the demoData table in the database again:

mysql> select * from demoData;

See what changes are made to the previous select.

After reading the data object, the developer can modify any attribute except the ID primary key, as long as it is modified:

db.update(Data object variable,'Modified property name 1','Modified property name 2',......)

jxTMS automatically submits the changes to the database.

Note 1: all modified attributes must be listed one by one in the update function, otherwise jxTMS will not submit the change of this attribute

Note 2: no matter cmd or prepareDisp function, all changes to the database, including create and update, are included in the same database transaction during the execution of the whole function. Any exception caused by any reason during the execution of the function will lead to the rollback of the database transaction and will not have a substantial impact on the database

Note 3: because exceptions will cause rollback of database operations, and cmd and prepareDisp functions are object functions in the function module, if the developer sets the data object as the object attribute of python object, the cached data object will be inconsistent with the data in the database in case of exceptions, such as:

@myModule.event('cmd', 'sayHello')
def sayHello(self, db, ctx):
	#Please replace 103897269075998 with the ID value you query from the database
	self.cachedORM = pyORM.getByID(db.getDBConn(),'demoData',103897269075998)
	self.cachedORM.Type = 'updated 123'
	self.cachedORM.Name = 1 / 0
	db.update(self.cachedORM,'Type','Name')

Since [1 / 0] will throw a divide by zero exception, self will appear in the response function executed when the user clicks other cmd buttons on the same interface cachedORM. Error that the type and the value in the database are inconsistent.

Note: each tab opened by clicking [Demo - > helloWorld] corresponds to a separate function object [function object newly created by calling New function], so the two helloworlds opened at the same time are completely independent

Therefore, for continuous business operations, using object variables as the cache of business data will obviously reduce the operation of reading the database with getByID, but it is likely to induce a serious error of inconsistent data. If you want to resolve this error, you must capture the abnormal and recover it, which greatly increases the workload, It may not guarantee the correctness of recovery. Therefore, the author strongly suggests that: do not use cross operation of object variables as the cache of business data. Just read it directly from the database when necessary.

Read data objects through other properties

We all read the data object through the getByID function. In addition, we can also read the data object through other properties:

dd = pyORM.get(db.getDBConn(),'Data class name','Attribute name','Attribute value')

However, please keep in mind that the attribute of the data class read in this way must have a unique value (such as serial number, student number, job number, etc.), otherwise the data read is likely to be randomly selected.

If you need to read through multiple attributes or multiple attributes, you must use the method of conditional query to read, please refer to the description in the next section.

Description of deletion

Because one of the purposes of jxTMS design is to reduce the threshold of developers as much as possible, the experience of developers may not be enough. Then accidental deletion will become a terrible hidden bomb, so jxTMS simply cancels the deletion ability of all ORM data objects.

Please keep in mind that all ORM data objects cannot be deleted, except for two special ORM data classes in jxTMS platform:

  • Relation: a data class used to describe the relationship between two ORM objects

  • tag: a data class used to mark an ORM data object

In other words, only these two classes provide deletion capability. All other ORM data classes of jxTMS, including those defined in java within jxTMS and those defined by the user in the data file, cannot be deleted once they are created.

So what if you really need to delete a data object? As demoData demonstrates, define a NoUsed Boolean attribute. When it needs to be deleted, set the attribute to True, and then filter all data rows with NoUsed=true during query.

Topics: Python