手写简单mybatis——代码体现保存用户和查询用户

先展示一下左侧的包和类,有关Student的可以忽略,我在下面代码中也不会体现,只是我自己在写代码时多写的类。

 

一、添加依赖。

当我们新建一个maven工程后,首先要在pom.xml里面添加依赖,即我们后续工程要用到的jar包。build部分是必不可少的,每个maven工程都要添加。

        <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.20</version>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>dev.tuxjsql</groupId>
                <artifactId>hikaricp-cp</artifactId>
                <version>2.1</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.2.1</version>
            </dependency>
            <dependency>
                <groupId>dom4j</groupId>
                <artifactId>dom4j</artifactId>
                <version>1.6.1</version>
            </dependency>
        </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <target>1.8</target>
                    <source>1.8</source>
                    <encoding>utf-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

二、在数据库新建一个表。

id为主键,如下图 

三、新建entity.User类

此User类和数据库的user表相对应,对user进行构造函数,getter和setter,toString

public class User {

    private int id;
    private String username;
    private String password;

    public User(){}

    public User(int id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    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;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

四、新建properties

druid.properties

druid.url=jdbc:mysql://127.0.0.1:3306/ssm?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
druid.username=root
druid.password=123456
druid.driverClassName=com.mysql.cj.jdbc.Driver

hikari.properties

username=root
password=123456
jdbcUrl=jdbc:mysql://127.0.0.1:3306/ssm?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
driverClassName=com.mysql.cj.jdbc.Driver

五、新建dao.UserDao接口

即对user要实现的功能

public interface UserDao {

    /**
     * 保存用户
     * @param user
     * @return
     */
    Integer saveUser(User user);

    /**
     * 根据id查找用户
     * @param id
     * @return
     */
    List<User> findUser(Integer id);
}

六、新建mapper.UserMapper.xml

即UserDao的映射

<!--UserDao的映射-->
<mapper namespace="com.xinzhi.dao.UserDao">
     <!--id和方法名一样-->
    <insert id="saveUser" resultType="com.xinzhi.entity.User" paramType="com.xinzhi.User">
        insert into user values(?,?,?)
    </insert>
    <select id="findUser" resultType="com.xinzhi.entity.User" paramType="com.xinzhi.User">
        select * from user where id = ?
    </select>
</mapper>

七、新建mybatis-config.xml

这里管理所有的mapper,标签mapper下可添加其他的mapper文件

<!--通过这个文件找到所有相关的Mapper文件-->
<mybatis>
    <!--找到数据源-->
    <dataSource>druid</dataSource>
    <mapper>mapper/userMapper.xml</mapper>
    <!--<mapper>mapper/studentMapper.xml</mapper>-->
</mybatis>

八、新建DaoWrapper类

实现序列化,这里的属性对应UserMapper.xml文件

public class DaoWrapper implements Serializable {

    /**
     * 类型,insert|update|delete
     */
    private String type;

    /**
     *  返回值的类型
     */
    private String resultType;

    /**
     * 参数的类型
     */
    private String paramType;

    /**
     *  sql语句
     */
    private String sql;

    public DaoWrapper(){}

    public DaoWrapper(String type, String resultType, String paramType, String sql) {
        this.type = type;
        this.resultType = resultType;
        this.paramType = paramType;
        this.sql = sql;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getResultType() {
        return resultType;
    }

    public void setResultType(String resultType) {
        this.resultType = resultType;
    }

    public String getParamType() {
        return paramType;
    }

    public void setParamType(String paramType) {
        this.paramType = paramType;
    }

    public String getSql() {
        return sql;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }

    @Override public String toString() {
        return "DaoWrapper{" +
                "type='" + type + '\'' +
                ", resultType='" + resultType + '\'' +
                ", paramType='" + paramType + '\'' +
                ", sql='" + sql + '\'' +
                '}';
    }
}

九、新建DataSourceFactory类,创建数据源

其实这个应该放在前面,因为在写mybatis-config.xml文件时,就要确定是要用druid还是hikari

/**
 * 数据源工厂
 * 简单工厂的应用
 */
public class DataSourceFactory {

//    public static void main(String[] args) {
//        // druid为魔术值,阿里规约里面写要避免
//        DataSource hikari = DataSourceFactory.createDataSource("druid");
//        System.out.println(hikari);
//    }

    public static final String DARASOURC_TYPE_HIKARI = "hikari";
    public static final String DARASOURC_TYPE_DRUID = "druid";


    public static DataSource createDataSource(String type){
        // 创建数据源
        DataSource dataSource = null;
        Properties properties = new Properties();
        if(DARASOURC_TYPE_HIKARI.equals(type)){
            try {
            properties.load(DataSourceFactory.class.getClassLoader().getResourceAsStream("hikari.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        HikariConfig hikariConfig = new HikariConfig(properties);
        dataSource = new HikariDataSource(hikariConfig);

        } else if (DARASOURC_TYPE_DRUID.equals(type)){
            try {
                properties.load(DataSourceFactory.class.getClassLoader().getResourceAsStream("druid.properties"));
            } catch (IOException e) {
                e.printStackTrace();
            }
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.configFromPropety(properties);
            dataSource = druidDataSource;
        }
        return dataSource;
    }
}

十、新建Session类

public class Session {

    /**
     * 每个会话都保持一个连接
     */
    private Connection connection;

    private Map<String, Map<String,DaoWrapper>> env;


    public Session(Connection connection, Map<String, Map<String, DaoWrapper>> env) {
        this.connection = connection;
        this.env = env;
    }

    // 开始会话
    public void begin(){
        try {
            connection.setAutoCommit(false);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    // 提交
    public void commit(){
        try {
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    // 回滚
    public void rollback(){
        try {
            connection.rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public Connection getConnection() {
        return connection;
    }

    public <T> T getMapper(Class clazz) {
        T t = (T)Proxy.newProxyInstance(Session.class.getClassLoader(),
                new Class[]{clazz}, new SqlInvocationHandler(connection,env.get(clazz.getName())));
        return t;
    }
}

十一、新建SqlInvocationHandler类

实现InvocationHandler,这个类即Session类最后调用的new SqlInvocationHandler(connection,env.get(clazz.getName()),我们把原本的InvocationHandler抽取出来成了一个类

public class SqlInvocationHandler implements InvocationHandler {

    private Connection connection;

    private Map<String,DaoWrapper> env;

    public SqlInvocationHandler(Connection connection,  Map<String, DaoWrapper> env) {
        this.connection = connection;
        this.env = env;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // 拿到包装
        DaoWrapper wrapper = env.get(method.getName());

        PreparedStatement statement = connection.prepareStatement(wrapper.getSql());

        // 对每一种sql语句进行独立的操作
        if ("insert".equals(wrapper.getType())) {
            String paramType = wrapper.getParamType();
            // 暂定传入一个对象
            Class<?> clazz = args[0].getClass();
            Field[] fields = clazz.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                fields[i].setAccessible(true);
                statement.setObject(i + 1, fields[i].get(args[0]));
            }
            return statement.executeUpdate();
        } else if ("delete".equals(wrapper.getType())) {
            for (int i = 0; i < args.length; i++) {
                statement.setObject(i + 1, args[i]);
            }
            return statement.executeUpdate();
        } else if ("select".equals(wrapper.getType())) {
            for (int i = 0; i < args.length; i++) {
                statement.setObject(i + 1, args[i]);
            }
            ResultSet result = statement.executeQuery();
            List list = new ArrayList();
            while (result.next()) {
                Class<?> clazz = Class.forName(wrapper.getResultType());
                Object object = clazz.newInstance();
                Field[] fields = clazz.getDeclaredFields();
                for (int i = 0; i < fields.length; i++) {
                    fields[i].setAccessible(true);
                    fields[i].set(object, result.getObject(fields[i].getName()));
                }
                list.add(object);
            }
            return list;
        }
        return null;
    }
}

十二、新建SessionFactory类

public class SessionFactory {

    private DataSource dataSource;

    /**
     *  第一个参数String表示UserMapper里的namespace
     *  第二个参数String表示id即方法名
     *  第三个参数DaoWrapper表示剩下的所有内容:类型,返回值类型,参数类型,sql语句
     */
    private Map<String, Map<String,DaoWrapper>> env = new HashMap<>(8);

    public SessionFactory(String configPath) {
       parseConfigXml(configPath);
    }

    /**
     *  解析配置文件
     * @param configPath
     */
    private void parseConfigXml(String configPath) {

        try{
            // 解析数据源
            InputStream resource = SessionFactory.class.getClassLoader().getResourceAsStream(configPath);
            SAXReader reader = new SAXReader();
            Document read = reader.read(resource);
            Element ConfigRoot = read.getRootElement();

            Element dataSourceElement = ConfigRoot.element("dataSource");
            dataSource = DataSourceFactory.createDataSource(dataSourceElement.getTextTrim());

            // 获取所有的mapper文件
            List mapperElements = ConfigRoot.elements("mapper");
            List<String> mapperPaths = new ArrayList<>();
            for (Object mapperElement : mapperElements) {
                Element element = (Element) mapperElement;
                mapperPaths.add(element.getTextTrim());
            }

            for (String mapperPath : mapperPaths) {
                Map<String, DaoWrapper> wrapper = new HashMap<>(8);
                Document document = reader.read(Session.class.getClassLoader().getResourceAsStream(mapperPath));
                Element root = document.getRootElement();
                String namespace = root.attribute("namespace").getValue();
                Iterator iterator = root.elementIterator();
                while (iterator.hasNext()) {
                    Element el = (Element) iterator.next();
                    String type = el.getName();
                    String id = el.attribute("id").getValue();
                    String resultType = el.attribute("resultType").getValue();
                    String paramType = el.attribute("paramType").getValue();
                    String sqlStr = el.getTextTrim();
                    wrapper.put(id, new DaoWrapper(type, resultType, paramType, sqlStr));
                }
                env.put(namespace, wrapper);
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    public Session openSession(){
        try {
            Session session = new Session(dataSource.getConnection(),env);
            return session;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
}

十三、测试结果

public class Test {

    public static void main(String[] args) {
        SessionFactory sessionFactory = new SessionFactory("mybatis-config.xml");
        Session session = sessionFactory.openSession();

        UserDao userDao = session.getMapper(UserDao.class);
        // 保存User
        //userDao.saveUser(new User(11,"a","b"));
        // 查阅User
        List<User> user = userDao.findUser(11);
        System.out.println(user);

    }
}

使用druid连接源

使用hikari连接源

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值