Java:SQLクエリを自動生成

この記事では、Javaクラスとオブジェクトに基づいてSQLクエリを自動的に生成するためのフレームワークの作成について説明します。 すでに多くの同様の既製のソリューションがあることを理解していますが、これを自分で実装したいと考えました。

フレームワークを作成するには、JavaアノテーションとJava Reflection APIを使用します。

それでは始めましょう。


いくつかのユースケースから始めましょう。


例1


特定のPersonクラスがあるとしましょう:

public static class Person { public String firstName; public String lastName; public int age; } 

次の呼び出しは、このクラスに基づいてテーブルを作成するSQLクエリを生成します。

 System.out.println(MySQLQueryGenerator.generateCreateTableQuery(Person.class)); 

実行すると、コンソールに次の出力が表示されます。

 CREATE TABLE `Person_table` ( `firstName` VARCHAR(256), `lastName` VARCHAR(256), `age` INT); 

例2


これで、注釈を使用した例はより複雑になります。

 @IfNotExists //   CREATE- IF NOT EXISTS @TableName("persons") //    public static class Person { @AutoIncrement //   AUTO_INCREMENT @PrimaryKey //      PRIMARY KEY public int id; @NotNull //   NOT NULL public long createTime; @NotNull public String firstName; @NotNull public String lastName; @Default("21") //    public Integer age; @Default("") @MaxLength(1024) //  VARCHAR public String address; @ColumnName("letter") //    public Character someLetter; } 

このクラスに基づいて、次のSQLクエリを取得します。

 CREATE TABLE IF NOT EXISTS `persons` ( `id` INT AUTO_INCREMENT, `createTime` BIGINT NOT NULL, `firstName` VARCHAR(256) NOT NULL, `lastName` VARCHAR(256) NOT NULL, `age` INT DEFAULT '21', `address` VARCHAR(1024) DEFAULT '', `letter` VARCHAR(1), PRIMARY KEY (`id`)); 

例3


また、データベースサーバーに接続し、そこに生成されたSQLクエリを送信できるMySQLClientクラスも作成しました。

クライアントには、 createTablealterTableinsertupdateselectのメソッドが含まれています

おおよそ次のように使用されます。

 MySQLClient client = new MySQLClient("login", "password", "dbName"); client.connect(); //    client.createTable(PersonV1.class); //   client.alterTable(PersonV1.class, PersonV2.class); //   PersonV2 person = new PersonV2(); person.createTime = new Date().getTime(); person.firstName = "Ivan"; person.lastName = "Ivanov"; client.insert(person); //     person.age = 28; person.createTime = new Date().getTime(); person.address = "Zimbabve"; client.insert(person); person.createTime = new Date().getTime(); person.firstName = "John"; person.lastName = "Johnson"; person.someLetter = 'i'; client.insert(person); List selected = client.select(PersonV2.class); //      System.out.println("Rows: " + selected.size()); for (Object obj: selected) { System.out.println(obj); } client.disconnect(); //    

仕組み


最初に、アルゴリズムはReflection APIを使用して、クラスのすべてのパブリックフィールドと非静的フィールドを反復処理します。 この場合のフィールドがアルゴリズムでサポートされている型(すべてのプリミティブデータ型、オブジェクト類似体、String型がサポートされている)の場合、データベースオブジェクトフィールドに関するデータを含むColumnオブジェクトがFieldオブジェクトから作成されます。 Javaデータ型とMySQL型の間の変換は自動的に行われます。 また、フィールドとクラスの注釈から、テーブルとそのフィールドのすべての修飾子が抽出されます。 次に、すべてのColumnからSQLクエリが形成されます。

 public static String generateCreateTableQuery(Class clazz) throws MoreThanOnePrimaryKeyException { List<Column> columnList = new ArrayList<>(); Field[] fields = clazz.getFields(); //     for (Field field: fields) { int modifiers = field.getModifiers(); if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) { //  public   static Column column = Column.fromField(field); //  Field  Column if (column!=null) columnList.add(column); } } /*   Column   */ } /***************************/ public static Column fromField(Field field) { Class fieldType = field.getType(); //     ColumnType columnType; if (fieldType == boolean.class || fieldType == Boolean.class) { columnType = ColumnType.BOOL; } /*     */ { } else if (fieldType==String.class) { columnType = ColumnType.VARCHAR; } else { //       return null; } Column column = new Column(); column.columnType = columnType; column.name = field.getName(); column.isAutoIncrement = field.isAnnotationPresent(AutoIncrement.class); /*    */ if (field.isAnnotationPresent(ColumnName.class)) { //      ColumnName columnName = (ColumnName)field.getAnnotation(ColumnName.class); String name = columnName.value(); if (!name.trim().isEmpty()) column.name = name; } return column; } 

同様に、ALTER TABLE、INSERT、およびUPDATEクエリが生成されます。 後者の2つの場合、列リストに加えて、そのフィールドの値もオブジェクトから抽出されます。

 Column column = Column.fromField(field); if (column!=null) { if (column.isAutoIncrement) continue; Object value = field.get(obj); if (value==null && column.hasDefaultValue) continue; //   :             if (column.isNotNull && value==null) { throw new NotNullColumnHasNullValueException(); } String valueString = value!=null ? "'" + value.toString().replace("'","\\'") + "'" : "NULL"; String setValueString = "`"+column.name+"`="+valueString; valueStringList.add(setValueString); } 

フレームワークにはResultSetExtractorクラスもあり、そのメソッドであるextractResultSet(ResultSet resultSet、Class clazz)は、resultSetからclazzクラスのオブジェクトのリストを自動的に作成します。 これは非常に簡単に行われるため、ここではその動作の原理について説明しません。

github では、フレームワークの完全なソースコードを見ることができます。 これで私はすべてを持っています。

Source: https://habr.com/ru/post/J330938/


All Articles