Moyen correct d’utiliser SsortingngBuilder en SQL

Je viens de trouver une construction de requête SQL comme celle-ci dans mon projet:

return (new SsortingngBuilder("select id1, " + " id2 " + " from " + " table")).toSsortingng(); 

Ce SsortingngBuilder atteint-il son objective, à savoir réduire l’utilisation de la mémoire?

J’en doute, car dans le constructeur, le «+» (opérateur Ssortingng concat) est utilisé. Cela prendra-t-il la même quantité de mémoire que l’utilisation de Ssortingng comme le code ci-dessous? J’ai compris, cela diffère quand on utilise SsortingngBuilder.append() .

 return "select id1, " + " id2 " + " from " + " table"; 

Les deux déclarations sont-elles égales dans l’utilisation de la mémoire ou non? Précisez s’il vous plaît.

Merci d’avance!

Modifier:

BTW, ce n’est pas mon code . Je l’ai trouvé dans un ancien projet. En outre, la requête n’est pas aussi petite que celle de mon exemple. 🙂

L’objective d’utiliser SsortingngBuilder, c’est-à-dire réduire la mémoire. Est-ce atteint?

Non pas du tout. Ce code n’utilise pas correctement SsortingngBuilder . (Je pense que vous l’avez mal citée, cependant, il n’y a sûrement pas de citations autour de id2 et de table ?)

Notez que le but (généralement) est de réduire la perte de mémoire plutôt que la mémoire totale utilisée, afin de faciliter un peu la vie sur le ramasse-miettes.

Cela prendra-t-il autant de mémoire que l’utilisation de Ssortingng comme ci-dessous?

Non, cela causera plus de perte de mémoire que le simple concat que vous avez cité. (Jusqu’à ce que l’optimiseur JVM voit que le SsortingngBuilder explicite dans le code n’est pas nécessaire et optimise le cas échéant.)

Si l’auteur de ce code veut utiliser SsortingngBuilder (il y a des arguments pour, mais aussi contre; voir note à la fin de cette réponse), mieux vaut le faire correctement (ici, je suppose qu’il n’y a pas de guillemets autour de id2 et table ):

 SsortingngBuilder sb = new SsortingngBuilder(some_appropriate_size); sb.append("select id1, "); sb.append(id2); sb.append(" from "); sb.append(table); return sb.toSsortingng(); 

Notez que j’ai répertorié some_appropriate_size dans le constructeur SsortingngBuilder , de sorte qu’il démarre avec une capacité suffisante pour le contenu complet que nous allons append. La taille par défaut utilisée si vous n’en spécifiez pas un est de 16 caractères , ce qui est généralement trop petit et entraîne le fait que SsortingngBuilder faire des réaffectations pour devenir plus grand (IIRC, dans le JDK Sun / Oracle, il se double [ou plus, s’il sait qu’il a besoin de plus pour satisfaire un append spécifique] à chaque fois qu’il manque de place.

Vous avez peut-être entendu que la concaténation de chaînes utilisera un SsortingngBuilder sous les couvertures si elle est compilée avec le compilateur Sun / Oracle. Cela est vrai, il utilisera un SsortingngBuilder pour l’expression globale. Mais il utilisera le constructeur par défaut, ce qui signifie que dans la majorité des cas, il devra procéder à une réallocation. C’est plus facile à lire, cependant. Notez que ce n’est pas le cas d’une série de concaténations. Ainsi, par exemple, cela utilise un SsortingngBuilder :

 return "prefix " + variable1 + " middle " + variable2 + " end"; 

Cela se traduit approximativement par:

 SsortingngBuilder tmp = new SsortingngBuilder(); // Using default 16 character size tmp.append("prefix "); tmp.append(variable1); tmp.append(" middle "); tmp.append(variable2); tmp.append(" end"); return tmp.toSsortingng(); 

Donc ce n’est pas grave, bien que le constructeur par défaut et la ou les réallocations ultérieures ne soient pas idéales, les chances sont assez bonnes – et la concaténation est beaucoup plus lisible.

Mais ce n’est que pour une seule expression. Plusieurs SsortingngBuilder sont utilisés pour cela:

 Ssortingng s; s = "prefix "; s += variable1; s += " middle "; s += variable2; s += " end"; return s; 

Cela finit par devenir quelque chose comme ça:

 Ssortingng s; SsortingngBuilder tmp; s = "prefix "; tmp = new SsortingngBuilder(); tmp.append(s); tmp.append(variable1); s = tmp.toSsortingng(); tmp = new SsortingngBuilder(); tmp.append(s); tmp.append(" middle "); s = tmp.toSsortingng(); tmp = new SsortingngBuilder(); tmp.append(s); tmp.append(variable2); s = tmp.toSsortingng(); tmp = new SsortingngBuilder(); tmp.append(s); tmp.append(" end"); s = tmp.toSsortingng(); return s; 

… ce qui est plutôt moche.

Il est toutefois important de se rappeler que dans la quasi-totalité des cas, le choix de la lisibilité (ce qui améliore la maintenabilité) importe peu, sauf en cas de problème de performance spécifique.

Lorsque vous avez déjà tous les “morceaux” que vous souhaitez append, il est inutile d’utiliser SsortingngBuilder . L’utilisation de SsortingngBuilder et de la concaténation de chaînes dans le même appel, conformément à votre exemple de code, est encore pire.

Ce serait mieux:

 return "select id1, " + " id2 " + " from " + " table"; 

Dans ce cas, la concaténation de chaîne se produit en fait à la compilation de toute façon, elle est donc équivalente à la plus simple:

 return "select id1, id2 from table"; 

En utilisant new SsortingngBuilder().append("select id1, ").append(" id2 ")....toSsortingng() réellement les performances dans ce cas, car il oblige la concaténation à être exécutée au moment de l’exécution , au lieu de au moment de la compilation . Oops.

Si le code réel génère une requête SQL en incluant des valeurs dans la requête, il s’agit d’un autre problème distinct , à savoir que vous devez utiliser des requêtes paramétrées, en spécifiant les valeurs dans les parameters plutôt que dans le SQL.

J’ai un article sur Ssortingng / SsortingngBuffer que j’ai écrit il y a un moment – avant que SsortingngBuilder soit disponible. Les principes s’appliquent à SsortingngBuilder de la même manière.

[[Il y a de bonnes réponses ici, mais je trouve qu’elles manquent encore d’informations. ]]

 return (new SsortingngBuilder("select id1, " + " id2 " + " from " + " table")) .toSsortingng(); 

Donc, comme vous l’avez souligné, l’exemple que vous donnez est simpliste, mais analysons-le quand même. Ce qui se passe ici, c’est que le compilateur fait le travail ici parce que "select id1, " + " id2 " + " from " + " table" sont des constantes. Donc cela se transforme en:

 return new SsortingngBuilder("select id1, id2 from table").toSsortingng(); 

Dans ce cas, évidemment, il est inutile d’utiliser SsortingngBuilder . Vous pourriez aussi bien faire:

 // the comstackr combines these constant ssortingngs return "select id1, " + " id2 " + " from " + " table"; 

Cependant, même si vous ajoutiez des champs ou d’autres éléments non constants, le compilateur utiliserait un SsortingngBuilder interne – il n’est pas nécessaire d’en définir un:

 // an internal SsortingngBuilder is used here return "select id1, " + fieldName + " from " + tableName; 

Sous les couvertures, cela se transforme en code à peu près équivalent à:

 SsortingngBuilder sb = new SsortingngBuilder("select id1, "); sb.append(fieldName).append(" from ").append(tableName); return sb.toSsortingng(); 

Vraiment, le seul moment où vous devez utiliser directement SsortingngBuilder c’est lorsque vous avez du code conditionnel. Par exemple, le code qui ressemble à ce qui suit est désespéré pour un SsortingngBuilder :

 // 1 SsortingngBuilder used in this line Ssortingng query = "select id1, " + fieldName + " from " + tableName; if (where != null) { // another SsortingngBuilder used here query += ' ' + where; } 

Le + dans la première ligne utilise une instance de SsortingngBuilder . Ensuite, le += utilise une autre instance de SsortingngBuilder . Il est plus efficace de faire:

 // choose a good starting size to lower chances of reallocation SsortingngBuilder sb = new SsortingngBuilder(64); sb.append("select id1, ").append(fieldName).append(" from ").append(tableName); // conditional code if (where != null) { sb.append(' ').append(where); } return sb.toSsortingng(); 

Une autre fois, j’utilise un SsortingngBuilder lorsque je construis une chaîne à partir d’un certain nombre d’appels de méthode. Ensuite, je peux créer des méthodes prenant un argument SsortingngBuilder :

 private void addWhere(SsortingngBuilder sb) { if (where != null) { sb.append(' ').append(where); } } 

Lorsque vous utilisez un SsortingngBuilder , vous devez surveiller simultanément toute utilisation de + :

 sb.append("select " + fieldName); 

Cela + provoquera la création d’un autre SsortingngBuilder interne. Cela devrait bien sûr être:

 sb.append("select ").append(fieldName); 

Enfin, comme le fait remarquer @TJrowder, vous devriez toujours deviner la taille du SsortingngBuilder . Cela permettra d’économiser le nombre d’objects char[] créés lors de l’augmentation de la taille du tampon interne.

Vous avez raison de penser que l’objective de l’utilisation du générateur de chaînes n’est pas atteint, du moins pas dans sa totalité.

Cependant, lorsque le compilateur voit l’expression "select id1, " + " id2 " + " from " + " table" il émet un code qui crée réellement un SsortingngBuilder en coulisse et y ajoute le résultat final. .

Mais bien sûr, quiconque regarde ce code doit penser qu’il est en quelque sorte retardé.

Dans le code que vous avez publié, il n’y aurait aucun avantage, car vous utilisez abusivement le SsortingngBuilder. Vous construisez la même chaîne dans les deux cas. En utilisant SsortingngBuilder, vous pouvez éviter l’opération + sur les chaînes à l’aide de la méthode append . Vous devriez l’utiliser de cette façon:

 return new SsortingngBuilder("select id1, ").append(" id2 ").append(" from ").append(" table").toSsortingng(); 

En Java, le type Ssortingng est une séquence de caractères inaltérable. Par conséquent, lorsque vous ajoutez deux chaînes, la machine virtuelle crée une nouvelle valeur de chaîne avec les deux opérandes concaténés.

SsortingngBuilder fournit une séquence de caractères modifiable, que vous pouvez utiliser pour concaténer différentes valeurs ou variables sans créer de nouveaux objects Ssortingng, ce qui peut parfois être plus efficace que de travailler avec des chaînes.

Cela fournit des fonctionnalités utiles, telles que la modification du contenu d’une séquence de caractères passée en paramètre dans une autre méthode, ce que vous ne pouvez pas faire avec des chaînes.

 private void addWhereClause(SsortingngBuilder sql, Ssortingng column, Ssortingng value) { //WARNING: only as an example, never append directly a value to a SQL Ssortingng, or you'll be exposed to SQL Injection sql.append(" where ").append(column).append(" = ").append(value); } 

Plus d’infos sur http://docs.oracle.com/javase/tutorial/java/data/buffers.html

Vous pouvez également utiliser MessageFormat aussi