So schreiben Sie das Persistenzschicht-Framework in Java handschriftlich
JDBC-Betriebsüberprüfung und Problemanalyse
Studenten, die Java lernen, müssen mit JDBC vertraut gewesen sein, mit dem wir während der Anfängerphase in Kontakt gekommen sind
# 🎜🎜#Der folgende Code stellt eine Verbindung zur Datenbank her, um Benutzertabelleninformationen abzufragen. Die Benutzertabellenfelder sind Benutzer-ID und Benutzername.Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; User user = new User(); try { // 加载数据库驱动 //Class.forName("com.mysql.jdbc.Driver"); Class.forName("com.mysql.cj.jdbc.Driver"); // 通过驱动管理类获取数据库链接 connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "mimashi3124"); // 定义sql语句?表示占位符 String sql = "select * from user where username = ?"; // 获取预处理statement preparedStatement = connection.prepareStatement(sql); // 设置参数,第⼀个参数为sql语句中参数的序号(从1开始),第⼆个参数为设置的参数值 preparedStatement.setString(1, "盖伦"); // 向数据库发出sql执⾏查询,查询出结果集 resultSet = preparedStatement.executeQuery(); // 遍历查询结果集 while (resultSet.next()) { int id = resultSet.getInt("id"); String username = resultSet.getString("username"); // 封装User user.setId(id); user.setUsername(username); } System.out.println(user); } catch ( Exception e) { e.printStackTrace(); } finally { // 释放资源 if (resultSet != null) { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if (preparedStatement != null) { try { preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } }
- Häufiges Erstellen und Freigeben von Datenbankverbindungen Dies führt zu einer Verschwendung von Systemressourcen und beeinträchtigt die Systemleistung.
- Wir schreiben SQL-Anweisungen in den Code. In tatsächlichen Anwendungen kann sich SQL stark ändern, und Änderungen in SQL erfordern Änderungen in Java Code.
- Die Verwendung von PreparedStatement zum Übergeben von Parametern an besetzte Symbole erfordert eine harte Codierung, da die Where-Bedingung der SQL-Anweisung ungewiss ist, sie kann mehr oder weniger sein, und das ist der Fall Um den SQL-Code zu ändern, muss er geändert werden. Das System ist nicht einfach zu warten.
- Es gibt eine harte Codierung (Name der Abfragespalte) beim Parsen der Ergebnismenge. SQL-Änderungen führen zu Änderungen im Parsing-Code und das System ist nicht einfach zu warten. Wenn die Datenbankeinträge in die Pojo-Objektanalyse eingekapselt werden können, ist dies einfacher Datenbankverbindungspool, um Verbindungsressourcen zu initialisieren und Ressourcen zu vermeiden. Das ist nicht besser, als SQL in einer Menge Java-Code umzuschreiben zu Tabellenfeldern.
- Für die Im Datenbankverbindungspool können wir die von c3p0 bereitgestellte ComboPooledDataSource direkt verwenden Datei. SQL allein reicht definitiv nicht aus. Schließlich müssen wir erst eine Verbindung zur Datenbank herstellen, bevor die SQL-Anweisung irgendeine Bedeutung hat. Daher müssen die Datenkonfigurationsinformationen zuerst in XML und dann in der SQL-Anweisung definiert werden.
- 1. Definieren Sie die Konfigurations-XML-Datei Wir erstellen eine neue sqlMapConfig.xml, definieren die Datenquelleninformationen und fügen zwei SQL-Anweisungen hinzu. ParameterType ist der SQL-Ausführungsparameter. und resultType ist die Methode, die die Entität zurückgibt.
- Der Code lautet wie folgt (verschiedene Versionen der Datenbank verwenden möglicherweise unterschiedliche Treiberklassen): Da nun auch die XML-Dateidatenbankinformationen und die SQL-Anweisung verfügbar sind Definition ist auch verfügbar, welche anderen Probleme gibt es?
<configuration> <!--数据库连接信息--> <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/> <!-- <property name="driverClass" value="com.mysql.jdbc.Driver"/>--> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai"/> <property name="username" value="root"/> <property name="password" value="mimashi3124"/> <select id="selectOne" parameterType="org.example.pojo.User" resultType="org.example.pojo.User"> select * from user where id = #{id} and username =#{username} </select> <select id="selectList" resultType="org.example.pojo.User"> select * from user </select> </configuration>
Nach dem Login kopieren
<configuration> <!--数据库连接信息--> <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/> <!-- <property name="driverClass" value="com.mysql.jdbc.Driver"/>--> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai"/> <property name="username" value="root"/> <property name="password" value="mimashi3124"/> <!--引⼊sql配置信息--> <mapper resource="mapper.xml"></mapper> </configuration>
<mapper namespace="user"> <select id="selectOne" parameterType="org.example.pojo.User" resultType="org.example.pojo.User"> select * from user where id = #{id} and username =#{username} </select> <select id="selectList" resultType="org.example.pojo.User"> select * from user </select> </mapper>
public class User { private int id; private String username; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + '}'; } }
<properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.22</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> </dependency> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>jaxen</groupId> <artifactId>jaxen</artifactId> <version>1.1.6</version> </dependency> </dependencies>
Connect Als nächstes folgt das eigentliche Parsen. Da es viele Parsing-Codes gibt, erwägen wir, die Klasse zu kapseln, um das Parsing separat durchzuführen.
Definieren Sie die XMLConfigBuilder-Klasse, um die Datenbankkonfiguration zu parsen Information
public class Configuration { //数据源 private DataSource dataSource; //map集合: key:statementId value:MappedStatement private Map<String,MappedStatement> mappedStatementMap = new HashMap<>(); public DataSource getDataSource() { return dataSource; } public Configuration setDataSource(DataSource dataSource) { this.dataSource = dataSource; return this; } public Map<String, MappedStatement> getMappedStatementMap() { return mappedStatementMap; } public Configuration setMappedStatementMap(Map<String, MappedStatement> mappedStatementMap) { this.mappedStatementMap = mappedStatementMap; return this; } }
Definieren Sie die XMLMapperBuilder-Klasse, um die Datenbankkonfiguration zu analysieren. Information
public class MappedStatement { //id private String id; //sql语句 private String sql; //输⼊参数 private String parameterType; //输出参数 private String resultType; public String getId() { return id; } public MappedStatement setId(String id) { this.id = id; return this; } public String getSql() { return sql; } public MappedStatement setSql(String sql) { this.sql = sql; return this; } public String getParameterType() { return parameterType; } public MappedStatement setParameterType(String parameterType) { this.parameterType = parameterType; return this; } public String getResultType() { return resultType; } public MappedStatement setResultType(String resultType) { this.resultType = resultType; return this; } }
Jetzt können wir das Konfigurationsobjekt abrufen, indem wir die Konfigurationsanalysemethode aufrufen. Bei der tatsächlichen Verwendung hoffen wir jedoch auf jeden Fall, dass ich Ihnen Konfigurationsinformationen und SQL-Anweisungen geben und dann Ihre Methode aufrufen kann, um das Ergebnis zurückzugeben.
Also müssen wir auch eine Datenbankoperationsschnittstelle (Klasse) definieren 3. Definieren Sie die SQL-Operationsschnittstelle SqlSessionpublic class Resources {
public static InputStream getResourceAsSteam(String path) {
return Resources.class.getClassLoader().getResourceAsStream(path);
}
}
Nach dem Login kopieren
Konkrete Implementierung der Operationsschnittstelle SqlSession, Hier ist das Wichtigste. Die entsprechenden SQL-Informationen werden über die Anweisungs-ID gefunden und ausgeführt. Datenbankausführungslogik schreiben# 🎜🎜#public class Resources { public static InputStream getResourceAsSteam(String path) { return Resources.class.getClassLoader().getResourceAsStream(path); } }
Die selectList-Methode in der Datenbankoperationsklasse DefaultSqlSession ruft die Methode simpleExcutor.query() auf
public class XMLConfigBuilder { private Configuration configuration; public XMLConfigBuilder() { this.configuration = new Configuration(); } public Configuration parserConfiguration(InputStream inputStream) throws DocumentException, PropertyVetoException, ClassNotFoundException { Document document = new SAXReader().read(inputStream); Element rootElement = document.getRootElement(); List<Element> propertyElements = rootElement.selectNodes("//property"); Properties properties = new Properties(); for (Element propertyElement : propertyElements) { String name = propertyElement.attributeValue("name"); String value = propertyElement.attributeValue("value"); properties.setProperty(name,value); } //解析到数据库配置信息,设置数据源信息 ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(); comboPooledDataSource.setDriverClass(properties.getProperty("driverClass")); comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl")); comboPooledDataSource.setUser(properties.getProperty("username")); comboPooledDataSource.setPassword(properties.getProperty("password")); configuration.setDataSource(comboPooledDataSource); //将configuration传入XMLMapperBuilder中做sql语句解析。 XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(this.configuration); List<Element> mapperElements = rootElement.selectNodes("//mapper"); for (Element mapperElement : mapperElements) { String mapperPath = mapperElement.attributeValue("resource"); InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(mapperPath); xmlMapperBuilder.parse(resourceAsStream); } return configuration; } }
Die obigen Kommentare sind detaillierter und der Prozess ist# 🎜🎜#
#🎜 🎜#Rufen Sie die auszuführende SQL-Anweisung ab, rufen Sie Parameter auf und geben Sie Parameter gemäß der entsprechenden Anweisungs-ID zurück.
Parsen Sie den SQL-Platzhalter und legen Sie die Aufrufparameter fest Ermitteln Sie den entsprechenden Wert durch Reflektion und legen Sie die SQL-Anweisungsparameter fest , schließen Sie die Einstellung der Objekteigenschaften ab und geben Sie schließlich das Ergebnis zurück.
Durch die obigen Schritte haben wir die Datenbankkonfiguration und die SQL-Anweisungsinformationen erhalten. Die Datenbankbetriebsklasse SqlSession ist definiert, aber wir rufen die Parsing-Konfigurationsdatei nirgendwo auf.
我们还需要一个东西把两者给串起来,这里我们可以使用工厂模式来生成SqlSession
使用工厂模式创建SqlSession
public interface SqlSessionFactory { public SqlSession openSession(); }
public class DefaultSqlSessionFactory implements SqlSessionFactory{ private Configuration configuration; public DefaultSqlSessionFactory(Configuration configuration) { this.configuration = configuration; } @Override public SqlSession openSession() { return new DefaultSqlSession(configuration); } }
同时为了屏蔽构建SqlSessionFactory工厂类时获取Configuration的解析过程,我们可以使用构建者模式来获得一个SqlSessionFactory类。
public class SqlSessionFactoryBuilder { public SqlSessionFactory build(InputStream inputStream) throws PropertyVetoException, DocumentException, ClassNotFoundException { XMLConfigBuilder xmlConfigerBuilder = new XMLConfigBuilder(); Configuration configuration = xmlConfigerBuilder.parserConfiguration(inputStream); SqlSessionFactory sqlSessionFactory = new DefaultSqlSessionFactory(configuration); return sqlSessionFactory; } }
5.调用测试
终于好了,通过以上几个步骤我们现在可以具体调用执行代码了。
public static void main(String[] args) throws Exception { InputStream resourceAsSteam = Resources.getResourceAsSteam("sqlMapConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsSteam); SqlSession sqlSession = sqlSessionFactory.openSession(); User user = new User(); user.setId(1); user.setUsername("盖伦"); User user2 = sqlSession.selectOne("user.selectOne", user); System.out.println(user2); List<User> users = sqlSession.selectList("user.selectList"); for (User user1 : users) { System.out.println(user1); } }
代码正确执行,输出
⾃定义框架优化
上述⾃定义框架,解决了JDBC操作数据库带来的⼀些问题:例如频繁创建释放数据库连接,硬编
码,⼿动封装返回结果集等问题,现在我们继续来分析刚刚完成的⾃定义框架代码,有没有什么问题呢?
问题如下:
dao的实现类中存在重复的代码,整个操作的过程模板重复(创建sqlsession,调⽤sqlsession⽅ 法,关闭sqlsession)
dao的实现类中存在硬编码,调⽤sqlsession的⽅法时,参数statement的id硬编码
我们可以使用代理模式,生成代理对象,在调用之前获取到执行方法的方法名、具体类。这样我们就能获取到statementId。
为SqlSession类新增getMappper方法,获取代理对象
public interface SqlSession { public <E> List<E> selectList(String statementId, Object... param) throws Exception; public <T> T selectOne(String statementId,Object... params) throws Exception; //为Dao接口生成代理实现类 public <T> T getMapper(Class<?> mapperClass); }
public class DefaultSqlSession implements SqlSession { private Configuration configuration; private Executor simpleExcutor = new SimpleExecutor(); public DefaultSqlSession(Configuration configuration) { this.configuration = configuration; } @Override public <E> List<E> selectList(String statementId, Object... param) throws Exception { MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId); List<E> query = simpleExcutor.query(configuration, mappedStatement, param); return query; } @Override public <T> T selectOne(String statementId, Object... params) throws Exception { List<Object> objects = selectList(statementId, params); if (objects.size() == 1) { return (T) objects.get(0); } else { throw new RuntimeException("返回结果过多"); } } @Override public <T> T getMapper(Class<?> mapperClass) { Object proxyInstance = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // selectOne String methodName = method.getName(); // className:namespace String className = method.getDeclaringClass().getName(); //statementId String statementId = className+'.'+methodName; Type genericReturnType = method.getGenericReturnType(); //判断是否实现泛型类型参数化 if (genericReturnType instanceof ParameterizedType){ List<Object> objects = selectList(statementId,args); return objects; } return selectOne(statementId,args); } }); return (T) proxyInstance; } }
定义业务数据dao接口
public interface IUserDao { //查询所有用户 public List<User> findAll() throws Exception; //根据条件进行用户查询 public User findByCondition(User user) throws Exception; }
接下来我们只需获取到代理对象,调用方法即可。
public class Main2 { public static void main(String[] args) throws Exception { InputStream resourceAsSteam = Resources.getResourceAsSteam("sqlMapConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsSteam); SqlSession sqlSession = sqlSessionFactory.openSession(); //获取到代理对象 IUserDao userDao = sqlSession.getMapper(IUserDao.class); List<User> all = userDao.findAll(); for (User user1 : all) { System.out.println(user1); } } }
Das obige ist der detaillierte Inhalt vonSo schreiben Sie das Persistenzschicht-Framework in Java handschriftlich. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen



Leitfaden zur Quadratwurzel in Java. Hier diskutieren wir anhand eines Beispiels und seiner Code-Implementierung, wie Quadratwurzel in Java funktioniert.

Leitfaden zur perfekten Zahl in Java. Hier besprechen wir die Definition, Wie prüft man die perfekte Zahl in Java?, Beispiele mit Code-Implementierung.

Leitfaden zum Zufallszahlengenerator in Java. Hier besprechen wir Funktionen in Java anhand von Beispielen und zwei verschiedene Generatoren anhand ihrer Beispiele.

Leitfaden für Weka in Java. Hier besprechen wir die Einführung, die Verwendung von Weka Java, die Art der Plattform und die Vorteile anhand von Beispielen.

Leitfaden zur Smith-Zahl in Java. Hier besprechen wir die Definition: Wie überprüft man die Smith-Nummer in Java? Beispiel mit Code-Implementierung.

In diesem Artikel haben wir die am häufigsten gestellten Fragen zu Java Spring-Interviews mit ihren detaillierten Antworten zusammengestellt. Damit Sie das Interview knacken können.

Java 8 führt die Stream -API ein und bietet eine leistungsstarke und ausdrucksstarke Möglichkeit, Datensammlungen zu verarbeiten. Eine häufige Frage bei der Verwendung von Stream lautet jedoch: Wie kann man von einem Foreach -Betrieb brechen oder zurückkehren? Herkömmliche Schleifen ermöglichen eine frühzeitige Unterbrechung oder Rückkehr, aber die Stream's foreach -Methode unterstützt diese Methode nicht direkt. In diesem Artikel werden die Gründe erläutert und alternative Methoden zur Implementierung vorzeitiger Beendigung in Strahlverarbeitungssystemen erforscht. Weitere Lektüre: Java Stream API -Verbesserungen Stream foreach verstehen Die Foreach -Methode ist ein Terminalbetrieb, der einen Vorgang für jedes Element im Stream ausführt. Seine Designabsicht ist

Anleitung zum TimeStamp to Date in Java. Hier diskutieren wir auch die Einführung und wie man Zeitstempel in Java in ein Datum konvertiert, zusammen mit Beispielen.
