简体   繁体   中英

java.sql.SQLException: no such column with the value I'm trying to insert

Project description

I'm trying to build a Java application for training foreign vocabulary using sqlite, currently without any GUI or much functionality. The sqlite database is very small: it has just one table (named vocabulary ) with two columns (named english and german ). The project is uploaded to Github .

what does the exec:java goal do in my project?

My vocabulary list is stored inside an external repository as a csv file. The file LoadVocabularyListIntoDB.java has the only purpose to parse that file and insert every line into the sqlite database.

what is the exact error?

I think, these lines of the maven compile logs are important:

java.lang.reflect.InvocationTargetException
[...]
Caused by: java.lang.RuntimeException: Cannot insert word pair into SQL Database.
    at voc.Database.insertWordPairIntoTable(Database.java:79)
    at voc.LoadVocabularyListIntoDB.insertVocabularyListIntoDB(LoadVocabularyListIntoDB.java:52)
[...]
Caused by: java.sql.SQLException: no such column: accountant
[...]
    at voc.Database.insertWordPairIntoTable(Database.java:76)

The last two lines, in particular the error message no such column: account proves that my parsing works, because this is actually the first column of the first line.

But I don't understand, why accountant is interpreted as a column, because my test for that method returns true, that means the method insertWordPairIntoTable() should work.

    @Test
    public void TestDataInsertion() {
        db = null;
        db = new Database();

        String f = "/tmp/test.db";
        db.setDBfilename(f);
        db.createNewEmptyDbFile();
        db.establishConnection();

        db.createBasicSqlTable();

        db.insertWordPairIntoTable("'time'", "'zeit'");
        assertEquals(db.getGermanTranslation("'time'"), "zeit");
    }

Secondly, I don't understand what is meant in my case by InvocationTargetException . I've read this stackOverflow thread: Java: InvocationTargetException , but surrounding the line theDB.insertWordPairIntoTable(englishWord, germanWord); with a try/catch block didn't help -- which is my invocation methed according to this line of the maven logs:

at voc.LoadVocabularyListIntoDB.insertVocabularyListIntoDB(LoadVocabularyListIntoDB.java:52)

A InvocationTargetException was never thrown there.

Please note: Because the file LoadVocabularyListIntoDB.java is executed while building the project, I can't debug that eg with breakpoints and such (at least, I haven't found a solution for that)

the complete logs:


directory listing

.
├── package-list
├── pom.xml
├── src
│   ├── main
│   │   └── java
│   │       └── voc
│   │           ├── Control.java
│   │           ├── Database.java
│   │           └── LoadVocabularyListIntoDB.java
│   └── test
│       └── java
│           └── voc
│               └── DatabaseTest.java
└── voc.iml

maven compile logs

$ mvn compile
[INFO] Scanning for projects...
[WARNING] 
[WARNING] Some problems were encountered while building the effective model for voc:voc:jar:1.0-SNAPSHOT
[WARNING] 'build.plugins.plugin.version' for org.apache.maven.plugins:maven-jar-plugin is missing. @ line 76, column 21
[WARNING] 
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING] 
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING] 
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building voc 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ voc ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /home/toogley/src/voc/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ voc ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 3 source files to /home/toogley/src/voc/target/classes
[INFO] 
[INFO] --- exec-maven-plugin:1.5.0:java (compilation preparations) @ voc ---
[WARNING] 
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:294)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.RuntimeException: Cannot insert word pair into SQL Database.
        at voc.Database.insertWordPairIntoTable(Database.java:79)
        at voc.LoadVocabularyListIntoDB.insertVocabularyListIntoDB(LoadVocabularyListIntoDB.java:52)
        at voc.LoadVocabularyListIntoDB.<init>(LoadVocabularyListIntoDB.java:25)
        at voc.LoadVocabularyListIntoDB.main(LoadVocabularyListIntoDB.java:57)
        ... 6 more
Caused by: java.sql.SQLException: no such column: accountant
        at org.sqlite.core.NativeDB.throwex(NativeDB.java:397)
        at org.sqlite.core.NativeDB._exec(Native Method)
        at org.sqlite.jdbc3.JDBC3Statement.executeUpdate(JDBC3Statement.java:116)
        at voc.Database.insertWordPairIntoTable(Database.java:76)
        ... 9 more
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.962 s
[INFO] Finished at: 2016-07-22T22:40:31+02:00
[INFO] Final Memory: 16M/159M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.5.0:java (compilation preparations) on project voc: An exception occured while executing the Java class. null: InvocationTargetException: Cannot insert word pair into SQL Database. no such column: accountant -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

Database.java

package voc;

import java.io.File;
import java.sql.*;
import java.util.ArrayList;

public class Database {
    private Connection conn = null;
    private Statement st = null;
    private String DBfilename  = null;

    public void setDBfilename(String pFilename)
    {
        this.DBfilename = pFilename;
    }

    public void createNewEmptyDbFile() {
        try {
            File file = new File(this.DBfilename);
            file.delete();
        } catch (Exception e) {
            throw new RuntimeException("Cannot create a new database file.",e);
        }
    }

    public void establishConnection() {
        try {
            // create database connection
            conn = DriverManager.getConnection("jdbc:sqlite:" + this.DBfilename);
            st = conn.createStatement();
            st.setQueryTimeout(30);
        } catch (SQLException e) {
            throw new RuntimeException("Cannont create a connection to the SQL database.",e);
        }
    }

    public void createBasicSqlTable() {
        try {
            String s = "create table vocabulary (english string, german string);";
            st.executeUpdate(s);
        } catch (SQLException e) {
            throw new RuntimeException("Cannot create a basic SQL Table.",e);

        }
    }

    /**
     * @returns the names of the SQL tables.
     */
    public ArrayList<String> showTables() {
        try {
            String s = "SELECT name FROM sqlite_master WHERE type='table';";
            ResultSet rs = st.executeQuery(s);

            ArrayList<String> SQLTableNames = new ArrayList<String>();
            while (rs.next())
            {
                 SQLTableNames.add(rs.getString(1));
            }

            return SQLTableNames;

        } catch (SQLException e) {
            throw new RuntimeException("SQL command to select all tables failed", e);
        }
    }

    /**
     * @param englishVoc: given word we want to learn
     * @param germanTranslation: translation of the given word
     */
    public void insertWordPairIntoTable(String englishVoc, String germanTranslation) {
        try {
            String s = "insert into vocabulary values("
                    + englishVoc + "," + germanTranslation + ");";
            st.executeUpdate(s);

        } catch (SQLException e) {
            throw new RuntimeException("Cannot insert word pair into SQL Database.", e);
        }
    }

    /**
     * @param pEnglishVoc: english word we want to learn (1st column of db)
     * @return the german translation of the parameter (2nd column of db)
     */
    public String getGermanTranslation(String pEnglishVoc) {
        ResultSet rs;
        try {
            String s = "select german from vocabulary where english="
                    + pEnglishVoc + ";";
            rs = st.executeQuery(s);
            return rs.getString(1);

        } catch (SQLException e) {
            throw new RuntimeException("Cannot get german translation for given english word.", e);
        }
    }
}

LoadVocabularyListIntoDB.java

package voc;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;

import java.io.IOException;
import java.nio.charset.Charset;

import java.net.MalformedURLException;
import java.net.URL;

import static java.nio.charset.Charset.forName;

public class LoadVocabularyListIntoDB {
    private Database theDB;

    public LoadVocabularyListIntoDB() {
        theDB = new Database();
        theDB.setDBfilename("database.db");
        theDB.createNewEmptyDbFile();
        theDB.establishConnection();
        theDB.createBasicSqlTable();

        this.insertVocabularyListIntoDB();
    }


    public void insertVocabularyListIntoDB() {
        URL url = null;

        try {
            url = new URL("https://raw.githubusercontent.com/toogley/voc-data/master/technology_and_society");
        } catch (MalformedURLException e) {
            throw new RuntimeException("URL of VocabularyList(" + url +") is malformed", e);
        }

        // CSVParser.parse(url,...) needs a Charset object
        Charset charset = forName("UTF-8");

        CSVParser parser = null;
        try {
            parser = CSVParser.parse(url, charset, CSVFormat.RFC4180);
        } catch (IOException e) {
            throw new RuntimeException("Failed to read from" + url, e);
        }

        for (CSVRecord csvRecord : parser) {
            String englishWord = csvRecord.get(0);
            String germanWord = csvRecord.get(1);

            theDB.insertWordPairIntoTable(englishWord, germanWord);
        }
    }

    public static void main(String[] args) {
        new LoadVocabularyListIntoDB();
    }
}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>voc</groupId>
    <artifactId>voc</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>voc</name>
    <url>http://maven.apache.org</url>
    <repositories>
        <repository>
            <id>tmate</id>
            <url>http://maven.tmatesoft.com/content/repositories/releases</url>
        </repository>
    </repositories>
    <dependencies>
        <dependency>
            <groupId>org.xerial</groupId>
            <artifactId>sqlite-jdbc</artifactId>
            <version>3.8.11.2</version>
        </dependency>
        <!-- http://mvnrepository.com/artifact/juni1t/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.dbunit</groupId>
            <artifactId>dbunit</artifactId>
            <version>2.5.2</version>
            <scope>test</scope>
        </dependency>


        <!-- The dependencies below are needed for inserting the vocabularyList into DB. -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-csv</artifactId>
            <version>1.3</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.5.0</version>
                <executions>
                    <execution>
                        <id>compilation preparations</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>test preparations</id>
                        <phase>test</phase>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <!-- adds every word pair of vocabulary csv list (https://github.com/toogley/voc-data)
                         to the SQL Database (while building) -->
                    <mainClass>voc.LoadVocabularyListIntoDB</mainClass>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>voc.Control</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

And this is why you should use a PreparedStatement with parameter placeholders instead of concatenating values into a query string. The problem is that in your test you add quotes around your values. This avoids the most basic problem of your statement, however the datasource you use doesn't have those quotes, so with the input:

accountant,Buchhalter

The query that gets executed is:

insert into vocabulary values(accountant,Buchalter)

Instead of your intention of:

insert into vocabulary values('accountant','Buchalter')

The solution is not to add the quotes, but instead rewrite your method to use a prepared statement:

public void insertWordPairIntoTable(String englishVoc, String germanTranslation) {
    try (PreparedStatement insert = connection.prepareStatement(
            "insert into vocabulary values(?,?)")) {
        insert.setString(1, englishVoc);
        insert.setString(2, germanTranslation);

        insert.executeUpdate();
    } catch (SQLException e) {
        throw new RuntimeException("Cannot insert word pair into SQL Database.", e);
    }
}

You might want to consider preparing the statement once, so you can reuse it.

Below an addendum for your other questions. If you need more information, you really need to ask a separate question per problem that addresses that single problem only.

The java.lang.reflect.InvocationTargetException is caused by executing this through Maven. Maven executes your code through reflection, and any exception thrown in your code gets wrapped in a java.lang.reflect.InvocationTargetException before it ends up inside Maven.

With regard to your debugging: I'm not sure what you mean by that. You should be able to debug this in any decent IDE; code executed during your build (which I think it isn't: maven executes it after the build phase), can always be debugged by executing it in isolation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM