जावा में SQL स्ट्रिंग बनाने का सबसे साफ तरीका


107

मैं डेटाबेस हेरफेर करने के लिए एक SQL स्ट्रिंग बनाना चाहता हूं (अपडेट, डिलीट, इंसर्ट, सेलेक्ट, उस तरह की चीज) - लाखों "+" s और कोट्स का उपयोग करते हुए भयानक स्ट्रिंग कॉनैट विधि के बजाय जो कि सबसे अच्छा नहीं है - वहां बेहतर तरीका होना चाहिए।

मैंने MessageFormat का उपयोग करने के बारे में सोचा था - लेकिन इसका उपयोग उपयोगकर्ता संदेशों के लिए किया जाना चाहिए, हालांकि मुझे लगता है कि यह एक उचित काम करेगा - लेकिन मुझे लगता है कि जावा एसक्यूएल पुस्तकालयों में SQL प्रकार के संचालन के लिए कुछ और गठबंधन करना चाहिए।

क्या ग्रूवी कोई अच्छा होगा?

जवाबों:


76

सबसे पहले तैयार बयानों में क्वेरी मापदंडों का उपयोग करने पर विचार करें:

PreparedStatement stm = c.prepareStatement("UPDATE user_table SET name=? WHERE id=?");
stm.setString(1, "the name");
stm.setInt(2, 345);
stm.executeUpdate();

दूसरी बात जो की जा सकती है वह यह है कि प्रॉपर्टीज फाइल में सभी क्वेश्चन रखें। एक क्वेरी में उदाहरण के लिए। कृपया फ़ाइल में उपरोक्त क्वेरी रख सकते हैं:

update_query=UPDATE user_table SET name=? WHERE id=?

फिर एक साधारण उपयोगिता वर्ग की मदद से:

public class Queries {

    private static final String propFileName = "queries.properties";
    private static Properties props;

    public static Properties getQueries() throws SQLException {
        InputStream is = 
            Queries.class.getResourceAsStream("/" + propFileName);
        if (is == null){
            throw new SQLException("Unable to load property file: " + propFileName);
        }
        //singleton
        if(props == null){
            props = new Properties();
            try {
                props.load(is);
            } catch (IOException e) {
                throw new SQLException("Unable to load property file: " + propFileName + "\n" + e.getMessage());
            }           
        }
        return props;
    }

    public static String getQuery(String query) throws SQLException{
        return getQueries().getProperty(query);
    }

}

आप अपने प्रश्नों का उपयोग इस प्रकार कर सकते हैं:

PreparedStatement stm = c.prepareStatement(Queries.getQuery("update_query"));

यह एक सरल समाधान है, लेकिन अच्छी तरह से काम करता है।


1
मैं इस तरह से एक साफ एसक्यूएल बिल्डर का उपयोग करना पसंद करता हूं: mentabean.soliveirajr.com
TraderJoeChicago

2
मेरा सुझाव है कि आप वक्तव्य के InputStreamअंदर रखें if (props == null)ताकि जब आपको इसकी आवश्यकता न हो तो आप इसे तत्काल न दें।
SyntaxRules

64

मनमाने ढंग से SQL के लिए, jOOQ का उपयोग करें । jOOQ वर्तमान में समर्थन करता है SELECT, INSERT, UPDATE, DELETE, TRUNCATE, और MERGE। आप इस तरह SQL बना सकते हैं:

String sql1 = DSL.using(SQLDialect.MYSQL)  
                 .select(A, B, C)
                 .from(MY_TABLE)
                 .where(A.equal(5))
                 .and(B.greaterThan(8))
                 .getSQL();

String sql2 = DSL.using(SQLDialect.MYSQL)  
                 .insertInto(MY_TABLE)
                 .values(A, 1)
                 .values(B, 2)
                 .getSQL();

String sql3 = DSL.using(SQLDialect.MYSQL)  
                 .update(MY_TABLE)
                 .set(A, 1)
                 .set(B, 2)
                 .where(C.greaterThan(5))
                 .getSQL();

SQL स्ट्रिंग प्राप्त करने के बजाय, आप इसे केवल jOOQ का उपयोग करके भी निष्पादित कर सकते हैं। देख

http://www.jooq.org

(अस्वीकरण: मैं jOOQ के पीछे कंपनी के लिए काम करता हूं)


क्या यह कई मामलों में एक खराब समाधान नहीं होगा क्योंकि आप dbms को "5", "8", आदि के लिए अलग-अलग मानों के साथ पहले से बयान देने में असमर्थ हैं? मुझे लगता है कि jooq के साथ निष्पादन करने से इसका समाधान हो जाएगा?
वेगा

@Vegard: आपको इस बात पर पूरा नियंत्रण है कि jOOQ को अपने SQL आउटपुट में बाइंड मान कैसे प्रस्तुत करना चाहिए: jooq.org/doc/3.1/manual/sql-building/bind-values । दूसरे शब्दों में, आपको चुना जाना है कि क्या प्रस्तुत करना है "?"या इनलाइन मानों को बाँधना है या नहीं।
लुकास एडर

ऐ, लेकिन sql के निर्माण के तरीके को साफ करने के संबंध में, यह मेरी नज़र में थोड़ा गन्दा कोड होगा यदि आप JOOQ का उपयोग नहीं कर रहे हैं। इस उदाहरण में आप A से 1, B से 2 आदि सेट करते हैं, लेकिन आपको इसे एक बार और करना होगा जब आप JOOQ के साथ निष्पादित नहीं कर रहे हैं।
वेगार्ड

1
@ वेजर्ड: कुछ भी नहीं आपको एक चर को jOOQ API से पास करने और SQL स्टेटमेंट को फिर से बनाने के लिए रखता है। इसके अलावा, आप jooq.org/javadoc/latest/org/jooq/Query.html#getBindValues ​​() का उपयोग करके या उनके नाम jooq.org/javadoc/latest/org/jooq का उपयोग करके उनके नाम से बाइंड मान निकाल सकते हैं /Query.html#getParams () । मेरे जवाब में बस एक बहुत ही सरल उदाहरण है ... मुझे यकीन नहीं है कि यह आपकी चिंताओं का जवाब है, हालांकि?
लुकास ईडर

2
इसका एक महंगा समाधान है।
सॉर्टर

15

एक तकनीक जिस पर आपको विचार करना चाहिए, वह है SQLJ - SQL बयानों को सीधे जावा में एम्बेड करने का एक तरीका। एक सरल उदाहरण के रूप में, आपके पास TestQueries.sqlj नामक फ़ाइल में निम्नलिखित हो सकते हैं:

public class TestQueries
{
    public String getUsername(int id)
    {
        String username;
        #sql
        {
            select username into :username
            from users
            where pkey = :id
        };
        return username;
    }
}

एक अतिरिक्त precompile कदम है जो आपकी .sqlj फ़ाइलों को लेता है और उन्हें शुद्ध जावा में अनुवादित करता है - संक्षेप में, यह विशेष ब्लॉक के लिए सीमांकित दिखता है

#sql
{
    ...
}

और उन्हें JDBC कॉल में बदल देता है। SQLJ का उपयोग करने के कई महत्वपूर्ण लाभ हैं:

  • पूरी तरह से अमूर्त JDBC परत - प्रोग्रामर को केवल जावा और एसक्यूएल के बारे में सोचने की जरूरत है
  • संकलन समय पर डेटाबेस के खिलाफ वाक्यविन्यास आदि के लिए आपके प्रश्नों की जांच करने के लिए अनुवादक बनाया जा सकता है
  • ":" उपसर्ग का उपयोग करके जावा चर को सीधे प्रश्नों में बाँधने की क्षमता

अधिकांश प्रमुख डेटाबेस विक्रेताओं के लिए अनुवादक के चारों ओर कार्यान्वयन हैं, इसलिए आपको आसानी से अपनी ज़रूरत की सभी चीज़ों को खोजने में सक्षम होना चाहिए।


विकिपीडिया के अनुसार, यह अब पुराना है।
ज़्यूस

1
लेखन के समय (जनवरी 2016) एसक्यूजे को विकिपीडिया पर बिना किसी संदर्भ के "पुराना" के रूप में संदर्भित किया जाता है । क्या इसे आधिकारिक तौर पर छोड़ दिया गया है? यदि हां, तो मैं इस उत्तर के शीर्ष पर एक चेतावनी चिपकाऊंगा।
एशले मर्सर

NB तकनीक अभी भी Oracle, 12c के नवीनतम संस्करण में उदाहरण के लिए समर्थित है । मैं मानता हूँ कि यह सबसे आधुनिक मानक नहीं है, लेकिन यह अभी भी काम करता है और इसके कुछ लाभ हैं (जैसे DB के विरुद्ध प्रश्नों का संकलन-समय सत्यापन) जो अन्य प्रणालियों में उपलब्ध नहीं हैं।
एशले मर्सर

12

मुझे आश्चर्य है कि अगर आप स्क्वीगल जैसी किसी चीज के बाद हैं । इसके अलावा कुछ बहुत उपयोगी है jDBI । हालांकि यह आपको प्रश्नों के साथ मदद नहीं करेगा।


9

मैं वसंत JDBC पर एक नज़र होगा । जब भी मुझे प्रोग्राम को SQL निष्पादित करने की आवश्यकता होती है, मैं इसका उपयोग करता हूं। उदाहरण:

int countOfActorsNamedJoe
    = jdbcTemplate.queryForInt("select count(0) from t_actors where first_name = ?", new Object[]{"Joe"});

यह किसी भी तरह के एसक्यूएल निष्पादन के लिए वास्तव में बहुत अच्छा है, विशेष रूप से क्वेरी; यह एक पूर्ण ORM की जटिलता को जोड़े बिना, आपको ऑब्जेक्ट्स को मैप करने में मदद करेगा।


मैं वास्तविक निष्पादित sql क्वेरी कैसे प्राप्त कर सकता हूं? मैं इसे लॉग इन करना चाहता हूं।
kodmanyagha

5

मैं स्प्रिंग के नामांकित JDBC पैरामीटर्स का उपयोग करना चाहता हूं, इसलिए मैं मानक मानक लिख सकता हूं जैसे "ब्लाह से जहां कोलएक्स = ': someValue'; मुझे लगता है कि यह बहुत पठनीय है।

एक वैकल्पिक स्ट्रिंग को एक अलग .sql फ़ाइल में आपूर्ति करने और एक उपयोगिता विधि का उपयोग करने में सामग्री को पढ़ने के लिए होगा।

ओह, स्क्वील में भी देखने लायक है: https://squill.dev.java.net/docs/tutorial.html


मेरा मानना ​​है कि आप का मतलब है कि आप बीनप्रोपरेट्टी एसक्लेपैरेटर्स सोर्स का उपयोग कर रहे हैं? मैं लगभग आपके साथ सहमत हूं, जिस कक्षा का मैंने उल्लेख किया है वह कड़ाई से सेम का उपयोग करते समय शांत है, लेकिन अन्यथा मैं ऑब्जेक्ट बनाने के लिए कस्टम ParameterizedRowMapper का उपयोग करने की सलाह दूंगा।
एस्को

काफी नहीं। आप नामांकित JDBC पैरामीटर के साथ किसी भी SqlParameterSource का उपयोग कर सकते हैं। इसने मेरी जरूरत को बीन की विविधता के बजाय मैपस्क्लेपर्मीटर व्यास का उपयोग करने के लिए अनुकूल किया। किसी भी तरह से, यह एक अच्छा समाधान है। हालाँकि, RowMappers SQL पहेली के दूसरे पक्ष से निपटते हैं: परिणाम को वस्तुओं में बदलते हैं।
गैरीफ

4

मैं हाइबरनेट जैसे ओआरएम का उपयोग करने के लिए सिफारिशें देता हूं। हालांकि, निश्चित रूप से ऐसी स्थितियां हैं जहां यह काम नहीं करता है, इसलिए मैं कुछ सामान को टालने का यह मौका लूंगा, जिसे मैंने लिखने में मदद की है: SqlBuilder "बिल्डर" शैली का उपयोग करके गतिशील रूप से sql स्टेटमेंट बनाने के लिए एक जावा लाइब्रेरी है। यह काफी शक्तिशाली और काफी लचीला है।


4

मैं एक जावा सर्वलेट एप्लिकेशन पर काम कर रहा हूं जिसे एडहॉक रिपोर्टिंग उद्देश्यों के लिए बहुत गतिशील एसक्यूएल स्टेटमेंट बनाने की आवश्यकता है। एप्लिकेशन का मूल कार्य पूर्व-कोडित क्वेरी में नामित HTTP अनुरोध मापदंडों के एक समूह को खिलाने के लिए है, और आउटपुट का एक अच्छा स्वरूपित तालिका उत्पन्न करता है। मैंने अपने सभी SQL प्रश्नों को XML फ़ाइलों में संग्रहीत करने और उन्हें तालिका स्वरूपण सूचना के साथ रिपोर्टिंग एप्लिकेशन में लोड करने के लिए स्प्रिंग MVC और निर्भरता इंजेक्शन ढांचे का उपयोग किया। आखिरकार, रिपोर्टिंग पैरामीटर मौजूदा पैरामीटर मैपिंग फ्रेमवर्क की क्षमताओं से अधिक जटिल हो गए और मुझे अपना खुद का लिखना पड़ा। यह विकास में एक दिलचस्प अभ्यास था और जो कुछ भी मुझे मिल सकता था उससे कहीं अधिक मजबूत मैपिंग पैरामीटर के लिए एक रूपरेखा तैयार की।

नया पैरामीटर मैपिंग इस प्रकार है:

select app.name as "App", 
       ${optional(" app.owner as "Owner", "):showOwner}
       sv.name as "Server", sum(act.trans_ct) as "Trans"
  from activity_records act, servers sv, applications app
 where act.server_id = sv.id
   and act.app_id = app.id
   and sv.id = ${integer(0,50):serverId}
   and app.id in ${integerList(50):appId}
 group by app.name, ${optional(" app.owner, "):showOwner} sv.name
 order by app.name, sv.name

परिणामी ढांचे की सुंदरता यह थी कि यह HTTP अनुरोध मापदंडों को सीधे क्वेरी में उचित प्रकार की जाँच और सीमा जाँच के साथ संसाधित कर सकता है। इनपुट सत्यापन के लिए कोई अतिरिक्त मैपिंग की आवश्यकता नहीं है। ऊपर दिए गए उदाहरण के प्रश्न में, serverId नाम के पैरामीटर को यह सुनिश्चित करने के लिए जांचा जाएगा कि यह एक पूर्णांक तक जा सकता है और 0-50 की सीमा में था। पैरामीटर appId को पूर्णांक की एक सरणी के रूप में संसाधित किया जाएगा, जिसकी लंबाई सीमा 50 है। यदि फ़ील्ड शोऑनर हैमौजूद है और "सही" पर सेट है, उद्धरणों में SQL के बिट्स वैकल्पिक फ़ील्ड मैपिंग के लिए उत्पन्न क्वेरी में जोड़े जाएंगे। फ़ील्ड कई और पैरामीटर प्रकार के मैपिंग उपलब्ध हैं जिनमें SQL के वैकल्पिक खंडों के साथ आगे पैरामीटर मैपिंग शामिल हैं। यह क्वेरी मैपिंग के जटिल के रूप में अनुमति देता है क्योंकि डेवलपर के साथ आ सकता है। यहां तक ​​कि रिपोर्ट कॉन्फ़िगरेशन में यह निर्धारित करने के लिए भी नियंत्रण है कि किसी दिए गए क्वेरी में एक तैयारी के माध्यम से अंतिम मैपिंग होगी या बस एक पूर्व-निर्मित क्वेरी के रूप में चलाई जाएगी।

नमूने के लिए Http अनुरोध मान:

showOwner: true
serverId: 20
appId: 1,2,3,5,7,11,13

यह निम्न SQL का उत्पादन करेगा:

select app.name as "App", 
       app.owner as "Owner", 
       sv.name as "Server", sum(act.trans_ct) as "Trans"
  from activity_records act, servers sv, applications app
 where act.server_id = sv.id
   and act.app_id = app.id
   and sv.id = 20
   and app.id in (1,2,3,5,7,11,13)
 group by app.name,  app.owner,  sv.name
 order by app.name, sv.name

मुझे वास्तव में लगता है कि स्प्रिंग या हाइबरनेट या उन चौखटों में से एक को अधिक मजबूत मानचित्रण तंत्र की पेशकश करनी चाहिए जो कि प्रकारों की पुष्टि करता है, जटिल डेटा प्रकार जैसे सरणियों और ऐसी अन्य सुविधाओं के लिए अनुमति देता है। मैंने अपने इंजन को केवल अपने उद्देश्यों के लिए लिखा था, यह सामान्य रिलीज़ के लिए काफी पढ़ा नहीं गया है। यह इस समय केवल Oracle प्रश्नों के साथ काम करता है और सभी कोड एक बड़े निगम के हैं। किसी दिन मैं अपने विचारों को ले सकता हूं और एक नए ओपन सोर्स ढांचे का निर्माण कर सकता हूं, लेकिन मुझे उम्मीद है कि मौजूदा बड़े खिलाड़ियों में से एक चुनौती लेगा।


3

आप सभी वर्ग को हाथ से क्यों उत्पन्न करना चाहते हैं? क्या आपने हाइबरनेट जैसे एक ओआरएम को देखा है, आपकी परियोजना के आधार पर यह संभवत: कम से कम 95% आपको क्या चाहिए, इसे साफ-सुथरे तरीके से करें, फिर कच्ची एसक्यूएल, और अगर आपको अंतिम प्रदर्शन प्राप्त करने की आवश्यकता है, तो आप इसे बना सकते हैं एसक्यूएल क्वेश्चन जिन्हें हाथ से करने की जरूरत है।


3

आप MyBatis ( www.mybatis.org ) पर भी नज़र डाल सकते हैं । यह आपको अपने जावा कोड के बाहर एसक्यूएल स्टेटमेंट लिखने में मदद करता है और अन्य चीजों के बीच अपने जावा ऑब्जेक्ट में एसक्यूएल परिणामों को मैप करता है।


3

Google एक कमरा प्रदान करता है जिसे लाइब्रेरी पर्सिटेंस लाइब्रेरी कहा जाता है जो Android ऐप्स के लिए SQL लिखने का एक बहुत ही स्वच्छ तरीका प्रदान करता है , जो मूल रूप से अंतर्निहित SQLite डेटाबेस पर एक अमूर्त परत है । Bellow आधिकारिक वेबसाइट से लघु कोड स्निपेट है:

@Dao
public interface UserDao {
    @Query("SELECT * FROM user")
    List<User> getAll();

    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    List<User> loadAllByIds(int[] userIds);

    @Query("SELECT * FROM user WHERE first_name LIKE :first AND "
           + "last_name LIKE :last LIMIT 1")
    User findByName(String first, String last);

    @Insert
    void insertAll(User... users);

    @Delete
    void delete(User user);
}

लाइब्रेरी के लिए आधिकारिक डॉक्स में अधिक उदाहरण और बेहतर दस्तावेज हैं।

MentaBean नामक एक जावा ओआरएम भी है । इसमें अच्छी विशेषताएं हैं और लगता है कि एसक्यूएल लिखने का यह बहुत सरल तरीका है।


के अनुसार कमरे का प्रलेखन : Room provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite। तो, यह RDBMS के लिए एक सामान्य ORM पुस्तकालय नहीं है। यह मुख्य रूप से Android Apps के लिए है।
रफीअल्हमद

2

एक XML फ़ाइल पढ़ें।

आप इसे एक XML फ़ाइल से पढ़ सकते हैं। इसका रखरखाव और इसके साथ काम करना आसान है। वहाँ मानक STX, DOM, SAX पार्सर्स उपलब्ध हैं जो इसे जावा में कोड की कुछ पंक्तियाँ बनाने के लिए उपलब्ध हैं।

विशेषताओं के साथ अधिक करें

एसक्यूएल के साथ और अधिक करने में मदद करने के लिए आप टैग पर कुछ अर्थ संबंधी जानकारी रख सकते हैं। यह विधि का नाम या क्वेरी प्रकार या कुछ भी हो सकता है जो आपको कम कोड में मदद करता है।

maintaince

आप जार के बाहर xml डाल सकते हैं और आसानी से इसे बनाए रख सकते हैं। गुण फ़ाइल के रूप में समान लाभ।

रूपांतरण

XML एक्स्टेंसिबल है और आसानी से अन्य प्रारूपों के लिए परिवर्तनीय है।

उदाहरण

Metamug Rml संसाधन फ़ाइलों को sql के साथ कॉन्फ़िगर करने के लिए xml का उपयोग करता है।


यदि आप उन्हें पसंद करते हैं तो आप याम्ल या जसन का उपयोग कर सकते हैं। वे एक सादे गुण फ़ाइल में संग्रहीत करने से बेहतर हैं
सॉर्टर

सवाल यह है कि SQL को कैसे बनाया जाए। SQL का निर्माण करने के लिए, यदि आपको XML, Parser, Validation, आदि का उपयोग करना है तो यह ओवरबर्डन है। SQL बनाने के लिए XML को शामिल करने वाले अधिकांश शुरुआती प्रयासों को एनोटेशन के पक्ष में दूर किया जा रहा है। स्वीकार किए जाते हैं जवाब से पायोत्र Kochański है सरल और सुरुचिपूर्ण और बात करने के लिए - समस्या और पोषणीय को हल करती है। नोट: एक अलग भाषा में बेहतर SQL बनाए रखने के लिए कोई वैकल्पिक तरीका नहीं है।
रफीअल्हमद

मैंने अपनी पिछली टिप्पणी हटा दी I don't see a reason to make use of XML. , क्योंकि मैं इसे संपादित नहीं कर सका।
रफीअल्हमद

1

यदि आप SQL स्ट्रिंग्स को गुण फ़ाइल में रखते हैं और फिर पढ़ते हैं कि आप SQL स्ट्रिंग्स को एक सादे पाठ फ़ाइल में रख सकते हैं।

यह SQL प्रकार के मुद्दों को हल नहीं करता है, लेकिन कम से कम यह TOAD या sqlplus से कॉपी और पेस्ट करना बहुत आसान बनाता है।


0

तुम कैसे तैयार हो जाओ स्ट्रिंग संघनक, एक तरफ से तैयार में लंबे एसक्यूएल तार से तैयार (कि आप आसानी से एक पाठ फ़ाइल में प्रदान कर सकते हैं और वैसे भी एक संसाधन के रूप में लोड) कि आप कई लाइनों पर टूट?

आप सीधे SQL स्ट्रिंग्स नहीं बना रहे हैं? प्रोग्रामिंग में यह सबसे बड़ी संख्या है। कृपया ReadyedStatements का उपयोग करें, और डेटा को मापदंडों के रूप में आपूर्ति करें। यह SQL इंजेक्शन की संभावना को बहुत कम कर देता है।


लेकिन अगर आप जनता के लिए एक वेब पेज को उजागर नहीं कर रहे हैं - तो क्या SQL इंजेक्शन एक प्रासंगिक मुद्दा है?
विदर्भ

4
SQL इंजेक्शन हमेशा प्रासंगिक होता है, क्योंकि यह गलती से और साथ ही इरादे से भी हो सकता है।
सिल्के

1
@Vidar - अब आप वेब पेज को जनता के सामने उजागर नहीं कर सकते हैं , लेकिन यहां तक ​​कि कोड जो "हमेशा" आंतरिक होगा अक्सर किसी न किसी तरह का बाहरी एक्सपोज़र खत्म हो जाता है, जो लाइन से कुछ हद तक आगे निकल जाता है। और यह तेजी से और अधिक सुरक्षित है कि यह पहली बार राउंड की तुलना में बाद में मुद्दों के लिए पूरे कोडबेस को ऑडिट करने के लिए है ...
एंड्रीज डॉयल

4
यहां तक ​​कि एक String से तैयार करने की जरूरत है, नहीं?
स्टीवर्ट

हां, लेकिन जब तक आप एक सुरक्षित प्रिपेडस्टेशन का निर्माण करते हैं, तब तक एक स्ट्रिंग से एक रेडीस्टेमेंट का निर्माण करना सुरक्षित होता है। आप शायद उन्हें तैयार करने के लिए एक रेडीस्टेडमेंटब्यूएटल क्लास लिखें, ताकि चीजों को समेटने की गंदगी को छिपाया जा सके।
JeeBee
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.