Здесь и далее:
Написать в начале
Здесь я буду писать несколько статей, чтобы дать некоторое представление об этой структуре, включая некоторые примеры.
Я планирую в основном представить структуру ORM (объектно-реляционное отображение), которая находится внутри структуры и называется «TURBO» (турбина) (потому что это ядро системы, поэтому я хотел использовать двигатель в качестве имени). Позже я поделюсь компонентами структуры, такими как проверка разрешений, единый вход, мониторинг и передача.
В последнем коде была проведена модульная разбивка, и в то же время были представлены другие компоненты, используемые в проекте. Если вам интересно, вы можете скачать и посмотреть. Адрес: https://gitee.com/base100/turbo.git
Весь набор ORM основан на springjdbc и использует механизм отражения Java для реализации. Здесь у некоторых студентов может возникнуть вопрос: «Зачем создавать ещё один ORM, когда уже есть hibernate и MyBatis?»
Первоначальная цель
Мне не нравится hibernate и MyBatis из-за большого количества конфигураций XML, поэтому я хочу избежать конфигурации, если это возможно. Эта идея также продолжается в моих собственных продуктах: простота — это красота.
Поскольку я когда-то был администратором базы данных Oracle, я сам контролирую базовую сборку SQL, оставляя дверь открытой для будущей оптимизации, вместо того чтобы позволить hibernate и mybatis делать всё, сохраняя прозрачность и возможность вставлять собственные методы оптимизации на нижнем уровне.
Я хочу использовать объектный запрос, писать SQL и смешивать их по своему усмотрению.
Чтобы соответствовать моему интерфейсному фреймворку, сделать взаимодействие между слоями MVC более лёгким и избежать преобразования различных PO, BO, VO, DTO, POJO туда и обратно.
Бесшовное переключение между несколькими источниками данных, без изменения кода. Во-первых, конфигурация должна быть максимально простой, а во-вторых, нижний уровень должен поддерживать общие синтаксисы различных баз данных.
Поддержка нескольких источников данных проще.
Возможность динамически создавать источники данных.
Можно ли обойтись без слоя DAO в MVC?
Удобство подключения к различным таблицам и разделам запросов и т. д.
(50% первоначальной цели) Когда я был молод и безрассуден, у меня не было девушки, и я был одержим кодом, работая над ним до двух часов ночи. Я чувствовал необходимость создать что-то, что продемонстрировало бы мои навыки.
Волосы важны.
Давайте теперь рассмотрим этот ORM на примере.
В настоящее время ORM поддерживает следующие базы данных: Oracle, MySQL, SQLserver, PostgreSQL, с возможностью расширения поддержки других баз данных.
Этот текст будет следовать следующему процессу:
- Конфигурация источника данных;
- Конфигурация объектных отношений;
- Операции вставки, удаления, изменения и запроса, транзакции, операции с несколькими источниками данных и динамическое создание источников данных.
Можно одновременно настроить несколько источников данных, и драйвер не нужно настраивать (нижний уровень напрямую ищет различные драйверы баз данных в соответствии с URL-адресом соединения), которые являются старыми драйверами, которые не меняются десятилетиями, но каждый раз, когда они настраиваются, студенты ищут их в Baidu.
db.default.url=jdbc:mysql://localhost:3306/test
db.default.username=root
db.default.password=root
db.default.initPoolSize=5
db.default.maxPoolSize=5
db.default.schema=test
# Второй источник данных (может быть бесконечное количество), v2 ниже представляет псевдоним второго источника данных, который можно настроить по желанию. На самом деле он используется в операциях.
db.v2.url=jdbc:postgresql://10.237.33.127:5432/test
db.v2.username=test
db.v2.password=123456
db.v2.initPoolSize=5
db.v2.maxPoolSize=5
Мы внутренне называем весь поддерживаемый MVC трёхслойный объект как VO, и нет абсолютного стандарта. Мы используем аннотации (annotation), но мы постарались максимально упростить их. Позже мы представим, что MVC имеет только один слой, который может использоваться в качестве объекта переднего плана для получения значений формы и может быть непосредственно вставлен в базу данных в соответствии с конфигурацией annotation.
Приведу пример.
Сначала создайте таблицу!
Чтобы показать, что эта структура поддерживает различные типы полей, мы создали несколько типов полей с различными типами данных, таких как символьные, CLOB, BLOB и временные метки.
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` char(32) DEFAULT '' COMMENT 'Идентификатор пользователя',
`name` varchar(255) DEFAULT NULL COMMENT 'Имя пользователя',
`email` varchar(255) DEFAULT NULL COMMENT 'Электронная почта',
`head_sculpture` blob COMMENT 'Изображение профиля',
`resume` longtext COMMENT 'Резюме',
`ts` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'Отметка времени'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Посмотрите на аннотацию VO (короткая книга делает макет настолько раздражающим, что он не поддерживает вставку кода, поэтому здесь я сделал снимок экрана, get и set здесь опущены, но на самом деле они существуют).
На следующем рисунке видно, что все свойства, соответствующие именам полей базы данных, не требуют аннотаций. Они не вставляются в базу данных, но используются для приёма данных форм переднего плана. Свойства, использующие @WsdNotDbColumn, могут быть аннотированы.
@WsdTable(name="T_USER")
public class UserVo extends ModuleFeatureBean{
/**
* Идентификатор пользователя
*/
@WsdColumn(isId=true)
private String id;
/**
* Имя пользователя
*/
private String name;
/**
* Электронная почта пользователя
*/
private String email;
/**
* Резюме
*/
@WsdColumn(type=TYPE.CLOB)
private String resume;
/**
* Изображение профиля
*/
@WsdColumn(type=TYPE.BLOB,name="head_sculpture")
private byte[] headSculpture;
/**
* Отметка времени
*/
private Date ts;
/**
* Значение, полученное интерфейсом для использования на сервере, не вставляется в базу данных
*/
@WsdNotDbColumn
private String token;
Здесь давайте посмотрим на аннотации, связанные с ORM:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WsdTable {
/**
* Название схемы в данных
* @return
*/
String schema()default "";
/**
* Наименование таблицы
* @return
*/
String name() default "";
/**
* Требуется ли sharding (разделение таблиц), необходимо искать конфигурацию разделов, соответствующую текущей таблице, в class-path table_sharding.xml
* @return
*/
boolean sharding() default false;
}
Здесь определены сопоставления различных типов полей базы данных для удобства адаптации одного и того же псевдонима к различным типам баз данных.
Например, NUMBER может быть сопоставлен с («number», «int», «tinyint», «decimal», «float», «double», «bigint», «numeric»), представляя псевдонимы для разных баз данных с одинаковыми типами. Вот перевод текста на русский язык:
NUMBER(Integer.class, Long.class, Double.class, int.class, double.class, long.class), TIMESTEMP(Date.class), VARCHAR2(String.class), BLOB(byte[].class), CLOB(String.class);
private TYPE() {
this.equalClazz = new Class<?>[]{};
}
private Class<?>[] equalClazz;
private TYPE(Class<?>... equalClazz) {
this.equalClazz = equalClazz;
}
public Class<?>[] getequalClazz() {
return equalClazz;
}
} /**
数据库字段分组
@author 公众号:18岁fantasy
@2014-11-21 @下午7:53:24 */ public static enum DB_TYPE_GROUP { NUMBER("number", "int", "tinyint", "decimal", "float", "double", "bigint", "numeric"), TIMESTAMP("timestamp", "timestamp with local time zone", "timestamp with time zone"), DATE("date", "datetime", "time"), STR("varchar2", "varchar", "char", "nvarchar2", "nvarchar"), BLOB("blob"), CLOB("clob", "ntext", "text", "longtext");
private String[] dbType;
DB_TYPE_GROUP(String... dbType) { this.dbType = dbType; }
public String[] getDbType() { return dbType; }
### 3、配置启动扫描
Здесь нужно сказать, что в рамках проекта был разработан механизм запуска движка с конфигурационным файлом, который определяет местоположение объектов VO, которые должны быть просканированы. Несколько пакетов для сканирования разделяются вертикальной чертой.
Таким образом, при запуске проекта происходит сканирование этих пакетов и сохранение метаданных всех обнаруженных объектов VO в контенте или кэш-сервисе. Для более подробного ознакомления с процессом можно обратиться к исходному коду.
Сканирование реализовано аналогично тому, как это сделано в spring, и реализовано в классе ModuleParser.
В этом разделе рассматриваются примеры операций с данными, включая удаление, изменение, поиск и использование нескольких источников данных, а также использование вне среды spring. Все примеры доступны в классе DaoTest.
**
Уже есть список часто используемых методов для работы с базой данных**
4.1 Вставка данных Для небольших проектов мы обычно не пишем слой DAO. Вместо этого мы используем CM для прямого доступа к сервису через сервисный слой. CM — это класс, который служит точкой входа для сервисов (конечно, сервисы также могут быть внедрены с помощью spring).
Этот метод похож на тот, который используется в популярных фреймворках.
/**
* Тестирование вставки объекта
*/
@Test
public void testInsert() {
try {
UserVo u = new UserVo();
u.setId(UUIDGenerator.getUUID());
u.setName("n_n");
u.setEmail("email@163.com");
u.setHeadSculpture(FileUtil.readFileToByteArray(new File("d:\\hp.png")));
u.setResume("简历内容");
u.setTs(new Date());
CM.getDao().insertModule("Тестирование вставки объекта", u);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testBatchInsert() throws IOException {
try {
List<UserVo> users = new ArrayList<UserVo>();
for (int i = 0; i < 50; i++) {
UserVo u = new UserVo();
u.setId(UUIDGenerator.getUUID());
u.setName("n_" + i);
u.setEmail("email@" + i + ".com");
u.setHeadSculpture(FileUtil.readFileToByteArray(new File("d:\\hp.png")));
u.setResume("简历内容" + i);
u.setTs(new Date());
users.add(u);
}
CM.getDao().batchInsertModule("Тестирование пакетной вставки объекта", users);
} catch (DaoException e) {
e.printStackTrace();
}
}
4.2 Операции поиска
@Test
public void testListModule() {
try {
List<UserVo> users = CM.getDao().listModule("Тестирование поиска на основе объектов", UserVo.class, null);
CollectionUtil.printCollection(users);
} catch (DaoException e) {
e.printStackTrace();
}}
@Test
public void testGetById() {
try {
String[] idValuds = {"3f1d35b12ab544fdb73badc750e534e2"};
UserVo user = CM.getDao().getModuleById("Поиск по id", UserVo.class, idValuds);
FileUtil.writeByteArrayToFile(new File("d:\\hp2.png"), user.getHeadSculpture());
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}
}
Все условия объединены в классе WhereCondition, который использует цепную структуру для упрощения процесса. 4.5 Транзакции В рамках одной транзакции выполняется несколько DDL-операций.
@Test
public void doInSingleTransationCircle() {
try {
UserVo user = new UserVo();
user.setId("bc17b776423241479354f6a4e6a2e261");
user.setName("new_name");
Dao dao = CM.getDao();
CM.getDao().doInSingleTransationCircle("事务操作", new SingleTransationCircleWithOutResult() {
@Override
public void actionInCircle() throws RuntimeException {
try {
dao.insertModule("插入", user);
user.setEmail("email@1.1");
WhereCondition condition = new WhereCondition();
condition.where().lessThan("Ts", "2019-05-08 15:47:11");
dao.updateModule("修改", user, condition);
dao.deleteModuleById("删除", user);
} catch (DaoException e) {
throw new RuntimeException(e);
}
}
});
} catch (DaoException e) {
e.printStackTrace();
}
}
4.6 Операции с несколькими источниками данных
#默认数据库配置
db.default.url=jdbc:mysql://localhost:3306/test
db.default.username=root
db.default.password=root
db.default.initPoolSize=5
db.default.maxPoolSize=5
db.default.schema=test
#其他数据源
db.pg.url=jdbc:postgresql://10.237.33.127:5432/test
db.pg.username=test
db.pg.password=123456
db.pg.initPoolSize=5
db.pg.maxPoolSize=5
public class CM extends CmCommon{
private static final String PG_DBNAME = "pg";
/**
* 获另外的的数据源操作类
*/
public static Dao getPGDao() {
return getDao(PG_DBNAME);
}
}
@Test
public void multDataSource() {
try {
//默认数据源
CM.getDao().listModule("测试基于对象查询列表", UserVo.class, null);
//另外的数据源
CM.getPGDao().listModule("测试基于对象查询列表", UserVo.class, null);
} catch (DaoException e) {
e.printStackTrace();
}
}
4.7 Динамическое создание источника данных Используется в основном в ситуациях, когда через интерфейс добавляется источник данных, например, динамическое добавление базы данных для последующего мониторинга или динамическая конфигурация источника данных в ETL.
/**
* 可在非spring环境下使用各种方法。常用场景如,比如要动态添加一个对数据库对其进行监控
*/
public static void main(String[] args) throws Exception {
//数据源参数
DataSourceProperty dataSourceProperty = new DataSourceProperty();
dataSourceProperty.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSourceProperty.setUsername("root");
dataSourceProperty.setPassword("root");
dataSourceProperty.setInitialSize(1);
dataSourceProperty.setMaxActive(1);
Dao dmDao = DaoFactory.createDao("动态数据源数据源", dataSourceProperty);
List<Map<String, Object>> users = dmDao.listMap("查询", "select * from t_user where ts<?", new Object[] {"2019-5-8 15:08:43"});
CollectionUtil.printCollection(users);
}
Это всё, что касается введения в ORM в рамках данной структуры.
Вы можете загрузить код из указанного адреса Git и протестировать его шаг за шагом.
Ещё раз спасибо за вашу работу. Я надеюсь, что вы сможете использовать эту структуру для написания кода и создания фреймворка. Также приглашаю вас подписаться на мой публичный аккаунт, duomi88.
Также есть публичный аккаунт в WeChat, приглашаем подписаться.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )