如何让变量每次调用时自动从数据库获取最新值?
Great question! The core issue here is that Java's String (and primitive types) are immutable—once you assign a value to a variable like theName, it holds a fixed reference to that string value forever, unless you explicitly reassign it. To get the behavior you want (where every reference to "name" pulls the latest value from the database automatically), you need to wrap this database-fetching logic in a dedicated class.
The Problem with Your Current Approach
Right now, you're storing the name in a static String variable. When you call changeName(), you have to manually re-fetch the value and reassign it to theName—this is error-prone and not scalable if you need to access the name in multiple places.
Solution: Wrap the Database Fetch in a Custom Class
Instead of using a raw String, create a class that encapsulates the logic to fetch the latest name from the database every time you request it. This way, every call to get the name triggers a fresh database lookup.
Step 1: Create the Dynamic Wrapper Class
import java.sql.*; import java.util.HashMap; public class DynamicEmployeeName { private final String employeeId; public DynamicEmployeeName(String employeeId) { this.employeeId = employeeId; } public String get() throws ClassNotFoundException, SQLException { HashMap<String, String> infoHR = connectionInfoHR(); // Use prepared statement to avoid SQL injection! String query = "SELECT first_name FROM employees WHERE employee_id = ?"; Class.forName("com.mysql.cj.jdbc.Driver"); try (Connection con = DriverManager.getConnection(infoHR.get("url"), infoHR.get("uname"), infoHR.get("pass")); PreparedStatement st = con.prepareStatement(query)) { st.setString(1, employeeId); try (ResultSet rs = st.executeQuery()) { if (rs.next()) { return rs.getString("first_name"); } return "Employee not found"; } } catch (Exception e) { e.printStackTrace(); return "Failed to fetch name from database"; } } // Helper method for connection credentials private HashMap<String, String> connectionInfoHR() { HashMap<String, String> info = new HashMap<>(); info.put("url", "jdbc:mysql://localhost:3306/sql_hr"); info.put("uname", "root"); info.put("pass", "Culley1max1"); return info; } }
Step 2: Update Your Main Class to Use the Wrapper
import java.sql.SQLException; public class GroundControlToMajorTom { public static void main(String[] args) throws ClassNotFoundException, SQLException { // Create a dynamic name instance tied to employee ID 72913 DynamicEmployeeName theName = new DynamicEmployeeName("72913"); // Initial fetch (prints the original value, e.g., Jim) System.out.println(theName.get()); // Update the name in the database changeEmployeeName("Kass", "72913"); // Automatically gets the latest value (prints Kass) System.out.println(theName.get()); } // Updated with prepared statement to fix SQL injection risk public static void changeEmployeeName(String name, String ID) throws ClassNotFoundException, SQLException { String url = "jdbc:mysql://localhost:3306/sql_hr"; String uname = "root"; String pass = "Culley1max1"; String query = "UPDATE employees SET first_name = ? WHERE employee_ID = ?"; Class.forName("com.mysql.cj.jdbc.Driver"); try (Connection con = DriverManager.getConnection(url, uname, pass); PreparedStatement st = con.prepareStatement(query)) { st.setString(1, name); st.setString(2, ID); st.executeUpdate(); } } }
Critical Fix: SQL Injection Vulnerability
I noticed your original code uses Statement with string concatenation for queries—this is a massive security risk. Always use PreparedStatement with parameter placeholders (?) as shown above, which safely escapes user input and prevents attackers from manipulating your database.
Bonus: Optimize with Caching (Carefully)
If fetching from the database every time is too slow, you can add a short-lived cache to reduce database calls. Just make sure to invalidate the cache whenever you update the name:
public class DynamicEmployeeName { private final String employeeId; private String cachedName; private long cacheTimestamp; private static final long CACHE_DURATION_MS = 5000; // 5 seconds public String get() throws ClassNotFoundException, SQLException { long now = System.currentTimeMillis(); // Check if cache is expired or empty if (cachedName == null || now - cacheTimestamp > CACHE_DURATION_MS) { cachedName = fetchNameFromDB(); // Reuse your fetch logic here cacheTimestamp = now; } return cachedName; } // Call this after updating the database to invalidate the cache public void invalidateCache() { cachedName = null; } // ... rest of the class ... }
Then, in your changeEmployeeName method, add theName.invalidateCache() right after updating the database to ensure the next get() fetches fresh data.
Key Takeaways
- Immutable types like
Stringcan't auto-update their values—use a wrapper class with a getter method to handle dynamic fetching. - Never use string concatenation for SQL queries—always use
PreparedStatementto avoid injection attacks. - Caching can improve performance, but remember to invalidate it when data changes to keep values consistent.
内容的提问来源于stack exchange,提问作者YaBoyIsFat

