> Java > java지도 시간 > 본문

Java에서 지속성 계층 프레임워크를 직접 작성하는 방법

PHPz
풀어 주다: 2023-04-18 19:37:38
앞으로
1303명이 탐색했습니다.

JDBC 연산 검토 및 문제 분석

Java를 배우는 학생들은 반드시 jdbc에 노출되어 있을 것입니다. 초급 기간 동안 노출되었던 jdbc 연산을 검토해 보겠습니다.

다음 코드는 데이터베이스에 연결하여 사용자 테이블 정보를 쿼리합니다. 사용자 테이블 필드는 사용자 ID, 사용자 이름입니다.

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();
                }
            }
        }
로그인 후 복사

코드를 살펴보면 JDBC를 사용하여 데이터베이스를 운영할 때 다음과 같은 문제점을 발견할 수 있습니다.

  • 데이터베이스 연결을 자주 생성하고 해제하면 시스템 리소스가 낭비되어 시스템 성능에 영향을 미칩니다.

  • 코드에 SQL 문을 작성하면 코드를 유지 관리하기가 쉽지 않습니다. 실제 응용 프로그램에서는 SQL이 크게 변경될 수 있으며 SQL을 변경하려면 Java 코드를 변경해야 합니다.

  • prepareStatement를 사용하여 점유된 기호에 매개변수를 전달하는 데 하드 코딩이 있습니다. 왜냐하면 sql 문의 where 조건이 확실하지 않고 다소 다를 수 있으며 sql을 수정하려면 코드를 수정해야 하기 때문입니다. 유지 관리가 어려운 시스템.

  • 결과 집합 구문 분석에 하드 코딩(쿼리 열 이름)이 있습니다. SQL 변경으로 인해 구문 분석 코드가 변경되어 데이터베이스 레코드를 캡슐화할 수 있으면 구문 분석이 더 쉬워집니다. pojo 개체

문제 해결 아이디어

  • 데이터베이스 연결 풀을 사용하여 연결 리소스를 초기화하여 리소스 낭비를 방지하세요

  • SQL 문을 xml 구성으로 추출하세요. 이런 종류의 SQL 변경은 집중하면 됩니다. xml 파일에 저장하면 여러 개의 Java 코드로 SQL을 다시 작성하는 것보다 낫지 않습니다

  • 매개변수 하드 코딩 문제를 해결하려면 리플렉션, 내부 검사 및 기타 기술을 사용하여 엔터티를 테이블 필드에 자동으로 매핑할 수 있습니다.

지속성 계층 프레임워크를 직접 작성

다음으로 위의 문제를 하나씩 해결해 보겠습니다

데이터베이스 연결 풀의 경우 c3p0에서 제공하는 ComboPooledDataSource를 직접 사용할 수 있습니다

SQL의 문제를 해결하려면 하드코딩을 하려면 sql을 xml 파일로 작성하려면 xml 파일을 정의하는 것이 당연합니다.

SQL만으로는 충분하지 않습니다. 결국 SQL 문이 의미를 갖기 전에 먼저 데이터베이스에 연결해야 합니다. 따라서 xml에서 데이터 구성 정보를 먼저 정의한 후 sql 문에서 정의해야 합니다.

1. 구성 xml 파일 정의

새 sqlMapConfig.xml을 생성하고 데이터 소스 정보를 정의한 후 두 개의 SQL 문을 추가합니다. 매개변수 유형은 SQL 실행 매개변수이고 결과 유형은 메소드 반환 엔터티입니다.

코드는 다음과 같습니다(데이터베이스 버전에 따라 다른 드라이버 클래스를 사용할 수 있음).

<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>
로그인 후 복사

이제 xml 파일 데이터베이스 정보도 사용할 수 있고, sql 문 정의도 사용할 수 있는데, 또 어떤 문제가 있나요?

실제 SQL 작업에는 다양한 테이블이 포함되므로 이를 개선하고 각 테이블의 SQL 문을 별도의 XML에 넣어 구조를 더 명확하고 유지 관리하기 쉽게 만들었습니다.

최적화된 xml 구성은 이제 다음과 같습니다

sqlMapConfig.xml

<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.xml

<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>
로그인 후 복사

그런데 비즈니스 엔터티 User

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=&#39;" + username + &#39;\&#39;&#39; +
                &#39;}&#39;;
    }
}
로그인 후 복사

를 정의합니다. 2. 구성 파일을 읽습니다.

읽기가 완료되면, 스트림 형태가 될 것입니다. 존재하고 작동하기 어렵기 때문에 정보를 얻기 위해 구문 분석하고 이를 저장할 엔터티 객체를 생성해야 합니다.

Configuration: 기본 데이터베이스 정보 저장, Map< 고유 식별자, Mapper> 고유 식별자: 네임스페이스 + "." + idMappedStatement: sql 문, 입력 매개변수 유형, 출력 매개변수 유형 저장

xml 구문 분석을 위해 dom4j를 사용합니다

the maven dependency

코드는 다음과 같습니다(mysql 드라이버 버전은 실제 사용된 mysql 버전에 따라 조정됩니다):

<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>
로그인 후 복사

데이터베이스 구성 개체 Configuration

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;
    }
}
로그인 후 복사

Sql 문 정보 개체

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;
    }
}
로그인 후 복사

그런데 리소스를 정의합니다 xml 파일 스트림을 읽는 클래스

public class Resources {
    public static InputStream getResourceAsSteam(String path) {
        return Resources.class.getClassLoader().getResourceAsStream(path);
    }
}
로그인 후 복사

다음 단계는 실제 파싱입니다. 파싱 코드가 많기 때문에 별도로 파싱을 처리하도록 클래스를 캡슐화하는 것을 고려합니다

데이터베이스 구성 정보를 파싱하기 위해 XMLConfigBuilder 클래스를 정의합니다

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;
    }
}
로그인 후 복사

XMLMapperBuilder 클래스를 정의하여 데이터베이스 구성 정보를 구문 분석하세요

public class XMLMapperBuilder {

    private Configuration configuration;

    public XMLMapperBuilder(Configuration configuration) {
        this.configuration = configuration;
    }
    public void parse(InputStream inputStream) throws DocumentException,
            ClassNotFoundException {
        Document document = new SAXReader().read(inputStream);
        Element rootElement = document.getRootElement();
        String namespace = rootElement.attributeValue("namespace");
        List<Element> select = rootElement.selectNodes("select");
        for (Element element : select) { //id的值
            String id = element.attributeValue("id");
            String parameterType = element.attributeValue("parameterType"); //输⼊参数
            String resultType = element.attributeValue("resultType"); //返回参数
            //statementId,后续调用通过statementId,找到对应的sql执行
            String key = namespace + "." + id;
            //sql语句
            String textTrim = element.getTextTrim();
            //封装 mappedStatement
            MappedStatement mappedStatement = new MappedStatement();
            mappedStatement.setId(id);
            mappedStatement.setParameterType(parameterType);
            mappedStatement.setResultType(resultType);
            mappedStatement.setSql(textTrim);
            //填充 configuration
            configuration.getMappedStatementMap().put(key, mappedStatement);
        }
    }
}
로그인 후 복사

이제 구성을 호출할 수 있습니다. 구문 분석 메서드는 구성 개체를 가져옵니다. 그러나 실제 사용에서는 구성 정보와 SQL 문을 제공한 다음 메서드를 호출하여 결과를 반환할 수 있기를 바랍니다.
그러므로 데이터베이스 작업 인터페이스(클래스)도 정의해야 합니다.

3. SQL 작업 인터페이스 SqlSession을 정의합니다

public interface SqlSession {
	//查询多个
    public <E> List<E> selectList(String statementId, Object... param) throws Exception;

	//查询一个
    public <T> T selectOne(String statementId,Object... params) throws Exception;
}
로그인 후 복사

작업 인터페이스 SqlSession의 구체적인 구현 여기서는 주로 stateId를 통해 해당 SQL 정보를 찾아 실행합니다.

코드에서 simpleExcutor는 실제 데이터베이스 명령문 실행, 매개변수 캡슐화 및 기타 작업을 반환합니다

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("返回结果过多");
        }
    }
}
로그인 후 복사

4. 데이터베이스 실행 로직 작성

데이터베이스 작업 클래스 DefaultSqlSession의 selectList 메서드는 simpleExcutor.query() 메서드를 호출합니다

public class SimpleExecutor implements Executor {

    private Connection connection = null;

    @Override
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws Exception {
        //获取连接
        connection = configuration.getDataSource().getConnection();
        // select * from user where id = #{id} and username = #{username} String sql =
        String sql = mappedStatement.getSql();
        //对sql进⾏处理
        BoundSql boundSql = getBoundSql(sql);
        // 3.获取预处理对象:preparedStatement
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());

        // 4. 设置参数
        //获取到了参数的全路径
        String parameterType = mappedStatement.getParameterType();
        Class<?> parameterTypeClass = getClassType(parameterType);

        List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
        for (int i = 0; i < parameterMappingList.size(); i++) {
            ParameterMapping parameterMapping = parameterMappingList.get(i);
            String content = parameterMapping.getContent();

            //反射
            Field declaredField = parameterTypeClass.getDeclaredField(content);
            //暴力访问
            declaredField.setAccessible(true);
            Object o = declaredField.get(params[0]);

            preparedStatement.setObject(i+1,o);

        }
        // 5. 执行sql
        ResultSet resultSet = preparedStatement.executeQuery();
        String resultType = mappedStatement.getResultType();
        Class<?> resultTypeClass = getClassType(resultType);

        ArrayList<Object> objects = new ArrayList<>();

        // 6. 封装返回结果集
        while (resultSet.next()){
            Object o =resultTypeClass.newInstance();
            //元数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                // 字段名
                String columnName = metaData.getColumnName(i);
                // 字段的值
                Object value = resultSet.getObject(columnName);
                //使用反射或者内省,根据数据库表和实体的对应关系,完成封装
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                writeMethod.invoke(o,value);
            }
            objects.add(o);
        }
        return (List<E>) objects;
    }

    @Override
    public void close() throws SQLException {

    }

    private Class<?> getClassType(String parameterType) throws ClassNotFoundException {
        if(parameterType!=null){
            Class<?> aClass = Class.forName(parameterType);
            return aClass;
        }
        return null;

    }

    private BoundSql getBoundSql(String sql) {
        //标记处理类:主要是配合通⽤标记解析器GenericTokenParser类完成对配置⽂件等的解 析⼯作,其中
        //TokenHandler主要完成处理
        ParameterMappingTokenHandler parameterMappingTokenHandler = new
                ParameterMappingTokenHandler();
        //GenericTokenParser :通⽤的标记解析器,完成了代码⽚段中的占位符的解析,然后再根 据给定的
       // 标记处理器(TokenHandler)来进⾏表达式的处理
        //三个参数:分别为openToken (开始标记)、closeToken (结束标记)、handler (标记处 理器)
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}",
                parameterMappingTokenHandler);
        String parse = genericTokenParser.parse(sql);
        List<ParameterMapping> parameterMappings =
                parameterMappingTokenHandler.getParameterMappings();
        return new BoundSql(parse, parameterMappings);
    }
}
로그인 후 복사

위의 설명은 다음과 같습니다.

  • 의 경우 실행할 SQL 문을 가져와서 매개 변수를 호출하고 해당 명령문 ID에 따라 매개 변수를 반환합니다.

  • sql 자리 표시자를 구문 분석하고 호출 매개변수를 설정합니다

  • 파싱된 입력 매개변수 필드에 따라 리플렉션을 통해 해당 값을 얻고 sql 문 매개변수를 설정합니다

  • sql 문을 실행하고 리플렉션을 사용하여 데이터베이스 테이블과 엔터티 간의 해당 관계를 기반으로 객체 속성 설정을 완료하고 최종적으로 결과를 반환하는 자체 검사입니다.

위 단계를 통해 데이터베이스 구성 및 SQL 문 정보를 얻었습니다. 데이터베이스 작업 클래스 SqlSession이 정의되어 있지만 구문 분석 구성 파일을 어디에서나 호출하지 않습니다.

我们还需要一个东西把两者给串起来,这里我们可以使用工厂模式来生成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);
        }
    }
로그인 후 복사

代码正确执行,输出

Java에서 지속성 계층 프레임워크를 직접 작성하는 방법

⾃定义框架优化

上述⾃定义框架,解决了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+&#39;.&#39;+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);
        }
    }
}
로그인 후 복사

Java에서 지속성 계층 프레임워크를 직접 작성하는 방법

위 내용은 Java에서 지속성 계층 프레임워크를 직접 작성하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:yisu.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿