जेनेरिक तैयार स्टेटमेंट बनाते समय मुझे परेशानी का सामना करना पड़ रहा है: मेरे पास 8 एसक्यूएल टेबल हैं, जो सभी एक ही तरह से छेड़छाड़ की जाती हैं, इसलिए मैं एक अद्वितीय प्रबंधक बनाना चाहता हूं जो 8 में से किसी भी टेबल में सम्मिलित/चयन कर सके।
ऐसा करने के लिए, प्रत्येक तालिका में एक डिस्क्रिप्टर होता है, जो सम्मिलित करते समय तालिका के फ़ील्ड, उसका नाम और मानों की सरणी प्रदान कर सकता है।
प्रबंधक में, सम्मिलित करने के लिए तैयार विवरण निम्नलिखित रूप का होता है:
"INSERT INTO " + table_name + " VALUES (?)"
फिर, मैं गैप को कुछ इस तरह से भरता हूँ
myPreparedStatement.setString(1, values.getAllValues());
GetAllValues() विधि को एक स्ट्रिंग लौटानी चाहिए जिसमें हर फ़ील्ड हो, जैसे "'यह', 'Is', 3, 'example'"। मुझे स्ट्रिंग्स और नंबरों से कोई समस्या नहीं है, लेकिन मैं उन मानों में कोई तारीख नहीं जोड़ सकता...
उदाहरण के तौर पर 3 सितंबर, 2008 का उपयोग करते हुए, मैंने निम्नलिखित प्रारूपों का उपयोग किया: 2008-09-03, 08-09-03, 080903, 03092018, लेकिन सभी विफल रहे। मैंने यहां और वहां जो देखा उससे "yyMMdd" प्रारूप सबसे अच्छे विकल्प की तरह लग रहा था, लेकिन मुझे त्रुटि है:
"java.sql.SQLDataException: ORA-01843: not a valid month"
और मुझे पता नहीं क्यों... किसी ने भी इस मुद्दे का सामना पहले किया है?
मुझे पता है कि यहां बहुत सारी पोस्ट हैं जो डेटाबेस में तिथियां डालने की बात करती हैं, लेकिन वे सभी का उपयोग करती हैं
preparedStatement.setDate(pos, Date);
वक्तव्य, और मैं ऐसा नहीं कर सकता क्योंकि तिथियां मेरी सभी तालिकाओं में समान स्थिति में नहीं हैं।
संपादित करें:
जैसा कि टिप्पणी में पूछा गया है, यहां एक न्यूनतम नमूना है जो मैं जो करने की कोशिश कर रहा हूं उसे पुन: पेश करता हूं। यदि आप भी पुन: पेश करना चाहते हैं, तो मैं आपको कनेक्शन और डेटाबेस सेटअप को संभालने देता हूं:
public class Sample {
public void saveAll() throws ServiceException {
Connection c = null;
PreparedStatement ps = null;
String sql = "INSERT INTO " + getTableName() +" VALUES (?)";
try {
c = getConnection();
c.setAutoCommit(false);
batch = c.prepareStatement(sql);
batch.setString(getAllFieldValues());
int res = batch.executeUpdate();
c.commit();
} catch (BatchUpdateException b) {
throw new ServiceException("Erreur lors de l'exécution du batch", b);
} catch (SQLException s) {
throw new ServiceException("Impossible de sauvegarder les beans en base.", s);
} finally {
getManager().close(batch);
freeConnection(c);
}
}
public String getAllFieldValues() {
return "'Hello', 'World', 42, '171228'";
}
public String getTableName() {
return "myTableName";
}
}
3 जवाब
JDBC में generic preparedStatement
जैसी कोई चीज़ नहीं है। तालिका T में चार कॉलम सम्मिलित करने के लिए आपको उपयोग करना चाहिए
INSERT into T (col1,col2,col3,col4) values (?,?,?,?)
आप कॉलम नामों के साथ पहली सूची को छोड़ सकते हैं, लेकिन यह एक खराब अभ्यास है क्योंकि आप तालिका के वास्तविक स्तंभों पर भरोसा करते हैं जो बदल सकते हैं।
केवल उपयोग करना
INSERT into T values (?,?,?,?)
ठीक काम करें जब तक कि कोई कॉलम जोड़कर या छोड़कर तालिका को संशोधित न करे और बाद में विफल हो जाए।
सभी बाइंड वेरिएबल को 1 से शुरू होने वाले कॉलम के उपयुक्त प्रकार और इंडेक्स के साथ setXXX विधि के साथ अतिरिक्त सेट किया जाना चाहिए।
stmt.setInt(1,100)
stmt.setString(2,'xxx')
अगर मैं आपके प्रश्न को सही ढंग से समझ सकता हूं। तैयार विवरण में अपने दिनांक मान को गतिशील रूप से रखने के लिए आप अपने कस्टम कोड को दिनांक मान की जाँच करने के लिए सेटस्ट्रिंग () विधि को ओवरराइड कर सकते हैं या फिर।
या इसके बजाय यदि आपके पास यह जांचने के लिए स्थानीय विधि भी हो सकती है कि आने वाली स्ट्रिंग प्रारूप दिनांक की है या नहीं।
इसके लिए आप बस कुछ उपसर्ग संलग्न के साथ दिनांक स्ट्रिंग पास कर सकते हैं ताकि आप इसे कस्टम सेटस्ट्रिंग () विधि में देख सकें।
setString(String string, int position){
if(string.contains("SPECIFIC_PREFIX_CONSTANT")){
//batch.setDate(position, string.substring("REMOVE PREFIX AND ATTACH"));
}else{
//batch.setString(position, string);
}
}
ठीक है दोस्तों, मैं अपना काम करने में कामयाब रहा, आप सभी को बहुत-बहुत धन्यवाद! यदि कोई और मेरे प्रश्न पर समाप्त हो जाता है, तो मेरे पास अभी जो कोड है, मैं उसे फिर से लिखूंगा, जो काम करता है :)
इसलिए, जैसा कि पहले कहा गया है, हमारे पास एक प्रबंधक है जो डेटाबेस के साथ इंटरैक्ट करता है और जिसे उस तालिका के बारे में कोई जानकारी नहीं है जिसके साथ वह इंटरैक्ट करता है।
इस प्रबंधक की सेव विधि का कोड यहां दिया गया है:
public void saveAll(AbstractBeanClass[] values, String refSelected) {
// connexion setup
Connection c = null;
PreparedStatement batch = null;
// fetch table's fields, to prepare the placeholders
String fields = values[0].getAllFields();
String sql = "INSERT INTO " + values[0].getTableName() + " (" + fields + ") VALUES (";
StringBuffer places = new StringBuffer();
int [] res = null;
// Start at 1 to have one field left, to end the parenthesis
for(int i = 1; i < values[0].getNumberOfFields(); i++) {
places.append("?, ");
}
// last field
places.append("?)");
sql = sql.concat(places.toString()); // We now have a full (?, ..., ?)
try {
c = getConnection();
c.setAutoCommit(false);
batch = c.prepareStatement(sql);
// Filling the batch
int j = 1;
for(AbstractBeanClass bean : values) {
int i = 1;
for(String type : bean.getAllTypes()) {
switch(type) {
case "int" : {
batch.setInt(i, (int) bean.getOrderedValue(i));
}
break;
case "String" : {
batch.setString(i, (String)bean.getOrderedValue(i));
}
break;
case "Date" : {
batch.setDate(i, (java.sql.Date) bean.getOrderedValue(i));
}
break;
}
i++;
}
batch.addBatch();
// In case of numerous insertions, some Databases don't allow more than 1000 inserts at a time
if(j%1000 == 0) {
res = batch.executeBatch();
for(int k : res) {
if(k == Statement.EXECUTE_FAILED) {
getManager().close(batch);
freeConnection(c);
throw new RuntimeException("Error while inserting values.");
}
}
}
j++;
}
// last execution
res = batch.executeBatch();
for(int i : res) {
if(i == Statement.EXECUTE_FAILED) {
getManager().close(batch);
freeConnection(c);
throw new RuntimeException("Error while inserting values in database.");
}
}
c.commit();
logger.debug("Insertion succeeded, we inserted " + j + " lines.");
} catch (BatchUpdateException b) {
throw new RuntimeException("Error in batch : ", b);
} catch (SQLException s) {
throw new RuntimeException("Error : we couldn't save the values : ", s);
} finally {
getManager().close(batch);
freeConnection(c);
}
}
तो यह कार्यक्रम का मुख्य भाग है, लेकिन इसके लिए टेबल डिस्क्रिप्टर की आवश्यकता है। इसे सरल रखने के लिए, मैंने एक अमूर्त वर्ग बनाया जो मुझे आवश्यक विधियों की घोषणा करता है, और सभी टेबल डिस्क्रिप्टर इस वर्ग का विस्तार करते हैं, यहां घोषणा है:
package com.fr.sncf.fret.boctarification.domaine.referentiel;
import java.io.Serializable;
import java.text.SimpleDateFormat;
public abstract class DaoGenericReferentielBean implements Serializable {
private static final long serialVersionUID = 1L;
protected String allFields;
// the date Format used to insert the dates in base
protected final SimpleDateFormat format = new SimpleDateFormat("yy-MM-dd");
public DaoGenericReferentielBean() {
// empty constructor
}
/**
* Return all columns' names, ordered according to database's order
* @return
*/
public String getAllFields() {
return this.allFields;
}
/**
* Returns all values ordered by columns' order
* @return String
*/
public abstract String getAllFieldsValues();
/**
* @return the table name
*/
public abstract String getTableName();
/**
* @return the number of field in this table
*/
public abstract int getNumberOfFields();
/**
* Returns the ordered list of column's type
*/
public abstract String[] getAllTypes();
/**
* Return the value corresponding to the given index
* Values are treated here according to the database's columns order
* @param index the column's number
* @return an Object, either an int, or a String, or a Date
*/
public abstract Object getOrderedValue(int index);
}
अब आपको बस इस मॉडल के अनुसार अपनी तालिका का वर्णन करना है, आशा है कि यह मदद करेगा!
संबंधित सवाल
जुड़े हुए प्रश्न
नए सवाल
java
जावा एक उच्च स्तरीय प्रोग्रामिंग भाषा है। इस टैग का उपयोग तब करें जब आपको भाषा का उपयोग करने या समझने में समस्या हो। इस टैग का उपयोग शायद ही कभी किया जाता है और इसका उपयोग अक्सर [वसंत], [वसंत-बूट], [जकार्ता-ई], [Android], [javafx], [हडूप], [श्रेणी] और [मावेन] के साथ किया जाता है।