用 Java 编写数据库迁移器,内存问题(代码结构?)
我目前正在尝试使用 JDBC 将数据从 filemaker pro 11 传输到 MySQL。
我已经处理了设置每个连接的问题,并进行了有效的查询,并将数据安全地插入到 MySQL 中。
try {
results =
query.executeQuery("SELECT \"field one\", \"field two\" from table");
Connection con = DriverManager.getConnection("jdbc:mysql://website.com/database","user","password");
// Iterate through the results and print them to standard output
while (results.next()) {
String fname = results.getString("field one");
String lname = results.getString("field two");
System.out.println("Found user \"" + fname + " " + lname + "\"");
stmt = con.prepareStatement("INSERT ignore INTO table (idtable, name) values (?, ?)");
// some of the data I've been provided with is pretty horrific,
// so inserting safely is of large concern.
stmt.setString(1, fname);
stmt.setString(2, lname);
stmt.executeUpdate();
}
}
catch (SQLException e) {
System.out.println("Error retrieving data from database.");
e.printStackTrace();
//System.exit(1);
}
这对于较小的表(4 分钟内约 100,000 条记录)来说还可以,但其中一些非常非常大,会导致应用程序崩溃:(。
这需要能够至少运行一次才能完成完整填充,但是之后,我可以限制输出以获取上周
我之前在 VB.net 中编写的更改,并构建了大型插入,但我做了一个切换 - 我确实需要那个准备语句,因为当前数据库有各种里面有很多疯狂的角色,
谢谢,保罗·S 。
Error:
Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
at java.lang.StringCoding$StringDecoder.decode(StringCoding.java:151)
at java.lang.StringCoding.decode(StringCoding.java:191)
at java.lang.String.<init>(String.java:451)
at java.util.jar.Attributes.read(Attributes.java:401)
at java.util.jar.Manifest.read(Manifest.java:199)
at java.util.jar.Manifest.<init>(Manifest.java:69)
at java.util.jar.JarFile.getManifestFromReference(JarFile.java:182)
at java.util.jar.JarFile.getManifest(JarFile.java:163)
at sun.misc.URLClassPath$JarLoader$2.getManifest(URLClassPath.java:710)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:238)
at java.net.URLClassLoader.access$000(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:212)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:435)
at com.mysql.jdbc.PreparedStatement.getInstance(PreparedStatement.java:872)
at com.mysql.jdbc.ConnectionImpl.clientPrepareStatement(ConnectionImpl.java:1491)
at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4250)
at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4149)
at datasync2.FMProConnection.companyQuoteInsert(FMProConnection.java:686)
at datasync2.DataSync2View.jButton1ActionPerformed(DataSync2View.java:220)
at datasync2.DataSync2View.access$800(DataSync2View.java:22)
at datasync2.DataSync2View$4.actionPerformed(DataSync2View.java:124)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2012)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2335)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:404)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:253)
at java.awt.Component.processMouseEvent(Component.java:6268)
I'm currently attemping to transfer data away from filemaker pro 11 to MySQL using JDBC.
I've dealt with setting up the connection to each, and have queries that work, and insert the data safely into MySQL.
try {
results =
query.executeQuery("SELECT \"field one\", \"field two\" from table");
Connection con = DriverManager.getConnection("jdbc:mysql://website.com/database","user","password");
// Iterate through the results and print them to standard output
while (results.next()) {
String fname = results.getString("field one");
String lname = results.getString("field two");
System.out.println("Found user \"" + fname + " " + lname + "\"");
stmt = con.prepareStatement("INSERT ignore INTO table (idtable, name) values (?, ?)");
// some of the data I've been provided with is pretty horrific,
// so inserting safely is of large concern.
stmt.setString(1, fname);
stmt.setString(2, lname);
stmt.executeUpdate();
}
}
catch (SQLException e) {
System.out.println("Error retrieving data from database.");
e.printStackTrace();
//System.exit(1);
}
This works okay for smaller tables(~100,000 records in 4 mins), but some of these are very, very big and cause the application to crash :(.
This needs to be able to run at least once to do a full population, but after that I can limit the output to pick up changes made in say the last week.
I previously wrote this in VB.net, and constructed large inserts, but I've made a switch - and I really need that prepare statement, as the current database has all sorts of crazy characters in there.
Thanks, Paul S
Error:
Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
at java.lang.StringCoding$StringDecoder.decode(StringCoding.java:151)
at java.lang.StringCoding.decode(StringCoding.java:191)
at java.lang.String.<init>(String.java:451)
at java.util.jar.Attributes.read(Attributes.java:401)
at java.util.jar.Manifest.read(Manifest.java:199)
at java.util.jar.Manifest.<init>(Manifest.java:69)
at java.util.jar.JarFile.getManifestFromReference(JarFile.java:182)
at java.util.jar.JarFile.getManifest(JarFile.java:163)
at sun.misc.URLClassPath$JarLoader$2.getManifest(URLClassPath.java:710)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:238)
at java.net.URLClassLoader.access$000(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:212)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:435)
at com.mysql.jdbc.PreparedStatement.getInstance(PreparedStatement.java:872)
at com.mysql.jdbc.ConnectionImpl.clientPrepareStatement(ConnectionImpl.java:1491)
at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4250)
at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4149)
at datasync2.FMProConnection.companyQuoteInsert(FMProConnection.java:686)
at datasync2.DataSync2View.jButton1ActionPerformed(DataSync2View.java:220)
at datasync2.DataSync2View.access$800(DataSync2View.java:22)
at datasync2.DataSync2View$4.actionPerformed(DataSync2View.java:124)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2012)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2335)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:404)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:253)
at java.awt.Component.processMouseEvent(Component.java:6268)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您可能需要使用不同的 FileMaker JDBC 驱动程序。我认为 FileMaker 附带的 JDBC 驱动程序不支持流式结果集,这意味着它将所有数据加载到内存中。
如果您愿意,可以在 http://java.net/projects/woof/ 尝试我们的 FileMaker JDBC 驱动程序。它比 FileMaker 提供的驱动程序慢很多,因为它在(慢速)XML Web Publishing 接口上运行,但它会传输结果,因此不会耗尽内存。
You might need to use a different FileMaker JDBC driver. I don't think that the JDBC driver shipped by FileMaker supports streaming result sets, which means it loads all the data into memory.
If you'd like, you can try our FileMaker JDBC driver at http://java.net/projects/woof/. It is quite a bit slower than the driver supplied by FileMaker, because it runs over the (slow) XML Web Publishing interface, but it streams the results and thus should not run out of memory.
分批进行。
您可以从 100K 的批量大小开始,然后增加它,直到性能下降。
:
像这里 http://download.oracle.com/javase/1.3/docs/guide/jdbc/spec2/jdbc2.1.frame6.html
(更新源行上的标志或按特定顺序处理它们并保存最后一个)
循环1-4,直到源中的所有记录表已成功处理。
Do it in batches.
You could start with a batch size of 100K and increase it until performance degrades.
:
like here http://download.oracle.com/javase/1.3/docs/guide/jdbc/spec2/jdbc2.1.frame6.html
(either update a flag on the source row or process them in a certain order and save the last one)
loop 1-4 until all records in source table had been processed successfully.
ReadyStatement 是正确的选择;那里不用担心。
我必须查看描述崩溃的异常才能知道根本原因是什么,但我的猜测是您试图一次插入太多记录。我会将其分成更小的块,并在作为单个事务时提交每个块。您的事务日志不必以这种方式包含每个 INSERT。
PreparedStatement is the way to go; no worries there.
I'd have to see the exception that described the crash to know what the root cause is, but my guess is that you're trying to INSERT too many records at once. I'd break it into smaller chunks and commit each chunk as I went as a single transaction. Your transaction log doesn't have to contain every INSERT that way.
也许这可以解决问题:(
显式释放该语句,而不是等待 GC 为您执行此操作)
Maybe that would fix the problem:
(release the statement explicitly instead of waiting for the GC to do it for you)